在使用HttpException手動拋出異常時,希望跳轉到自定義的錯誤頁面,官方的文章中是這樣描述的。 可以使用\think\exception\HttpException類來拋出異常 一旦拋出了HttpException異常,可以支持定義單獨的異常頁面的模板地址,只需要在應用配置文件中增加: 然而 ...
在使用HttpException
手動拋出異常時,希望跳轉到自定義的錯誤頁面,官方的文章中是這樣描述的。
可以使用\think\exception\HttpException
類來拋出異常
// 拋出 HTTP 異常 throw new \think\exception\HttpException(404, '異常消息', null, [參數]);
一旦拋出了HttpException
異常,可以支持定義單獨的異常頁面的模板地址,只需要在應用配置文件中增加:
'http_exception_template' => [ // 定義404錯誤的重定向頁面地址 404 => APP_PATH.'404.html', // 還可以定義其它的HTTP status 401 => APP_PATH.'401.html', ]
然而如果你這些都做完了,關閉調試模式,你會發現還是跳轉到官方自定義的頁面上去了,並且你發現http狀態碼是500
,這是代碼有問題啊,我拋出的是404
啊。
然後打開log日誌,你會發現果然報錯了。
[ error ] [1]Uncaught think\exception\TemplateNotFoundException: template not exists:view/layout.html in /Applications/MAMP/htdocs/best.shiqidu.com/thinkphp/library/think/Template.php:1082 Stack trace:
這。。。
可怎麼辦。。。
只能看源碼找問題了。
你會發現這個方法被調用了兩次。
/** * 解析模板文件名 * @access private * @param string $template 文件名 * @return string|false */ private function parseTemplateFile($template) {...}
第一次時$template模板文件時能找到的。但是第二次也是一個相對路徑view/layout
,所以報錯了,繼續順藤摸瓜,發現這個函數。
/** * 編譯模板文件內容 * @access private * @param string $content 模板內容 * @param string $cacheFile 緩存文件名 * @return void */ private function compiler(&$content, $cacheFile) { // 判斷是否啟用佈局 if ($this->config['layout_on']) { if (false !== strpos($content, '{__NOLAYOUT__}')) { // 可以單獨定義不使用佈局 $content = str_replace('{__NOLAYOUT__}', '', $content); } else { // 讀取佈局模板 $layoutFile = $this->parseTemplateFile($this->config['layout_name']); if ($layoutFile) { // 替換佈局的主體內容 $content = str_replace($this->config['layout_item'], $content, file_get_contents($layoutFile)); } } } else { $content = str_replace('{__NOLAYOUT__}', '', $content); } ...
關鍵就是這裡了,如果你沒有{__NOLAYOUT__}
這個表示的話,它在渲染自定義404頁面時會去載入佈局文件(如果你在配置文件里開啟了佈局,如果沒開啟layout=true
,也不會報這個錯)。
而這個佈局文件的路徑是一個相對路徑,這時如果你拋出異常的地方不是在application
的controller
里,就找不到佈局文件了。所以就報錯了。
怎麼解決呢?其實也很簡單。給自定義的404頁面加上{__NOLAYOUT__}
就行了。
這一點官方文檔沒有說明,還在坑裡的同學可以參考改下。