運維記錄1——解決在Nginx下部署CRA項目,二級目錄不能訪問的問題

如果從頭開始搭建React項目,create-react-app通常是開發者的首選。畢竟不是誰都有精力去了解WebPack的複雜配置,而CRA將配置隱藏開箱即用的特性必然會受到普遍歡迎。

根目錄訪問

到了部署階段,我通常使用nginx作爲web容器,將項目部署到一個根目錄下訪問。如

# nginx配置
server {
  listen 80;
  server_name my.website.com;
  
  ...
  
  location / {
    alias /data/www/react-project/dist;
    index index.html
  }
}

那麼只要我們將項目文件放到對應的目錄下,重啓nginx即可開始訪問web頁面。

二級目錄訪問

有時我們有多個web項目,多個項目不可能同時掛在根目錄下,所以我們會劃分二級目錄來分別訪問各個web項目。如

問題1:CSS等資源加載失敗

此時,如果簡單將nginx配置的location改爲/project1,則會出現網頁無法訪問的錯誤。

# nginx配置
server {
  listen 80;
  server_name my.website.com;
  
  ...
  
  # location / {
  location /project1 {
    alias /data/www/react-project/dist;
    index index.html
  }
}

現象

從dev工具可以看出,html文件有取得,但css、js等資源引用失敗。css和js的文件路徑都是http://my.website.com/static/...(或css)。

分析

CRA(create-react-app)的項目配置默認是跑在根目錄下的。如果查看dist目錄下的html會發現,所有的css或js文件的引用路徑都是/開頭的絕對路徑。

解決

將打包路徑從絕對路徑改爲相對路徑:

# package.json
{
  ...
  "homepage": ".",   // 添加homepage屬性,將路徑改爲當前目錄
  ...
}

重新編譯後看到,所有的資源文件路徑都改過來了。

問題2:加載成功,網頁空白

重新上傳到服務器,更新dist目錄下的文件,重啓nginx後訪問網頁。

現象

結果發現,網頁仍然是空白一片。查看html的渲染結果,發現似乎js並沒有執行。

分析

在react-router-dom的例子中,通常使用的是BrowserRouter。這種類型的Router在向服務器發送請求時,如果相對於二級目錄的路由去指向對應的頁面路由,就會找不到資源,因此也就不會渲染。

解決

BrowserRouter有一個屬性叫做basename,就是用於解決此類問題。

...
import { Route, BrowserRouter as Router, Switch, Redirect } from 'react-router-dom';
...
...
  <Router basename='/project1'>
    <Switch>
      <Redirect exact key='index' path='/' to='/home' />
      { routes }
    </Switch>
  </Router>
...

問題3:訪問成功,刷新後404

修改以上配置並編譯部署,重啓nginx後可正常訪問網頁。但刷新後,網頁變爲一片空白。

現象

網頁顯示,在請求頁面路由如http://my.website.com/project... 時,該路由的請求狀態爲404。

分析

還是因爲BrowserRouter的問題,之前能正常訪問時因爲路由中設置了Redirect,所以能訪問到根目錄並自動跳轉到/home。但直接訪問則會訪問失敗。

解決

在nginx配置中加入try_files命令

  location /project1 {
    alias /data/www/react-project/dist;
    # index index.html
    try_files $uri /project1/index.html
  }

這樣,在請求$uri時如果找不到對應的資源,會fallback回去加載index.html。

問題解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章