專案:laravel + vue 實現前後端分離。
vue-router 預設 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新載入。
- hash URL 例如:
http://yoursite.com/#/user/id
。 - history 模式時,URL就像正常的 url,例如
http://yoursite.com/user/id
。
沒有特別的要求的話,hash模式亦正常訪問。好嘛,產品要求URL要像正常那樣的 —— history模式的。看看vue文件,要實現vue history模式也很簡單。vue 切換一下模式,本地測試ok啦。
接下來,看到還需要後臺配置支援:
因為VUE應用是個單頁客戶端應用,如果後臺沒有正確的配置,當使用者在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就不好看了。所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。
So,Nginx配置一下:
location / {
try_files $uri $uri/ /index.html;
}
沒錯,部署前端資源Nginx伺服器上,簡單加上一條通用匹配規則。
至此,vue 前端搞定了,但是。。。還是不行的!
原因是從前端伺服器訪問是正常了,但是域名指向的是後端伺服器,所以當vue router history模式url直接訪問時還是會404.
當到這裡,又回頭排查一下是不是前面哪裡搞錯了,仔細看下來,沒問題啊,完全按vue文件說明操作啦。
想一陣子,才找到思路:404是後端報出的,也就說Laravel給出的,laravel router 壓根就沒前端定義的路由。所以,當即一拍腦子,就想到是不是將laravel 異常處理在response出去前給中斷一下,將404處理交給前端再處理一下,那麼也只是需要在app/Exceptions/Handler
中render
方法加下判斷:
/**
* Render an exception into an HTTP response.
*
* @param IlluminateHttpRequest $request
* @param Exception $exception
* @return IlluminateHttpResponse
*/
public function render($request, Exception $exception)
{
// 解決vue history 地址丟失問題
if($exception instanceof SymfonyComponentHttpKernelExceptionNotFoundHttpException)
{
if ($exception->getStatusCode() == 404) {
return response()->view(`welcome`);
}
}
return parent::render($request, $exception);
}
解釋一下:welcome 就是載入了vue CSS和JS,也就是vue依賴檔案。
以上搞定前後端分離,vue history 404 問題!