Nginx部署前端項目實戰(zhàn)指南及常見錯誤
1. 前言與場景描述
在現(xiàn)代前后端分離的架構(gòu)中,前端通常使用 Vue.js、React 等框架開發(fā)。開發(fā)完成后,通過構(gòu)建工具(Webpack/Vite)打包成一堆靜態(tài)文件(HTML, CSS, JS, Images)。
我們的目標是:
將這些靜態(tài)文件放到服務(wù)器上,利用 Nginx 作為 Web 服務(wù)器響應(yīng)用戶的 HTTP 請求。同時,Nginx 還需要充當“反向代理”,將前端對 /api 的請求轉(zhuǎn)發(fā)給后端的 Java/Go/Python 服務(wù),從而解決跨域問題。
假設(shè)環(huán)境:
- 操作系統(tǒng):CentOS 7 / Ubuntu 20.04 或 Docker 環(huán)境
- 前端項目:一個標準的 Vue 3 項目
- 后端地址:
http://192.168.1.100:8080 - 域名:
www.example.com
2. 準備工作:獲取前端包
首先,你需要在本地開發(fā)環(huán)境中將代碼打包。
# 在項目根目錄下執(zhí)行 npm run build # 或者 yarn build
執(zhí)行完畢后,項目根目錄下會生成一個 dist(或 build)文件夾。結(jié)構(gòu)大致如下:
dist/ ├── css/ ├── js/ ├── img/ ├── favicon.ico └── index.html <-- 入口文件
關(guān)鍵點:你需要把這個 dist 文件夾完整地上傳到服務(wù)器的某個目錄,例如 /usr/share/nginx/html/my-app。
3. Nginx 基礎(chǔ)安裝與配置(Linux 宿主機模式)
如果直接在 Linux 服務(wù)器上運行 Nginx:
3.1 安裝 Nginx
# CentOS sudo yum install epel-release sudo yum install nginx # Ubuntu sudo apt update sudo apt install nginx # 啟動并設(shè)置開機自啟 sudo systemctl start nginx sudo systemctl enable nginx
3.2 配置文件結(jié)構(gòu)
Nginx 的主配置文件通常位于 /etc/nginx/nginx.conf。為了便于管理,我們通常不直接修改主文件,而是在 /etc/nginx/conf.d/ 目錄下創(chuàng)建一個新的 .conf 文件,例如 my-app.conf。
3.3 編寫最基礎(chǔ)的配置
新建文件 /etc/nginx/conf.d/my-app.conf:
server {
# 監(jiān)聽端口,HTTP 默認為 80
listen 80;
# 服務(wù)器域名或 IP
server_name www.example.com;
# 日志路徑(建議配置,方便排錯)
access_log /var/log/nginx/my-app.access.log;
error_log /var/log/nginx/my-app.error.log;
# 核心配置:靜態(tài)資源映射
location / {
# 指定靜態(tài)資源文件的根目錄
# 這里對應(yīng)你上傳 dist 文件夾的絕對路徑
root /usr/share/nginx/html/my-app;
# 指定默認首頁
index index.html index.htm;
}
}
測試并重載:
nginx -t # 檢查語法是否正確 nginx -s reload # 重載配置
此時,訪問 http://www.example.com,你應(yīng)該能看到你的頁面了。但是,這還只是個開始,接下來的配置才是重頭戲。
4. 進階配置一:解決 SPA(單頁應(yīng)用)刷新 404 問題
問題描述:
如果你的前端使用了 History 路由模式(例如 Vue Router 的 history mode),當你點擊頁面跳轉(zhuǎn)到 /user/profile 時一切正常,但如果你在 /user/profile 頁面點擊瀏覽器的刷新按鈕,或者直接復(fù)制這個 URL 打開,Nginx 會報 404 Not Found。
原因:
Nginx 默認會去 root 目錄下找名為 user 文件夾下的 profile 文件。但這是一個單頁應(yīng)用,實際上只有 index.html,不存在物理路徑 /user/profile。
解決方案:
利用 try_files 指令。
server {
listen 80;
server_name www.example.com;
root /usr/share/nginx/html/my-app;
index index.html;
location / {
# 核心指令 try_files
# 含義:嘗試按照順序訪問文件
# 1. $uri: 找有沒有對應(yīng)的具體文件(比如 style.css)
# 2. $uri/: 找有沒有對應(yīng)的目錄
# 3. /index.html: 如果前兩個都找不到,無條件重定向到 index.html
try_files $uri $uri/ /index.html;
}
}
這樣配置后,Nginx 發(fā)現(xiàn)找不到文件時,就會把請求交給 index.html,前端的 JS 路由接管 URL 并渲染正確的組件。
5. 進階配置二:反向代理(解決跨域與 API 轉(zhuǎn)發(fā))
問題描述:
前端代碼中請求接口寫的是 axios.get('/api/users')。
如果不配置代理,請求會發(fā)送到 http://www.example.com/api/users。但后端接口實際上在 http://192.168.1.100:8080/api/users。此外,如果前后端域名不同,還會產(chǎn)生 CORS 跨域問題。
解決方案:
在 Nginx 中配置 proxy_pass。
server {
# ... 省略前面的配置 ...
# 匹配所有以 /api/ 開頭的請求
location /api/ {
# 后端服務(wù)地址
# 注意:結(jié)尾是否有斜杠 '/' 區(qū)別很大,下面詳細說明
proxy_pass http://192.168.1.100:8080/;
# 代理設(shè)置(標準配置,直接復(fù)制即可)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 可選:如果后端接口響應(yīng)慢,可以增加超時時間
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
}
關(guān)于 proxy_pass 結(jié)尾斜杠的“天坑”說明:
- 帶斜杠:
proxy_pass http://ip:port/;- 請求
http://domain/api/user-> 轉(zhuǎn)發(fā)到http://ip:port/user - Nginx 會把
/api/切掉。
- 請求
- 不帶斜杠:
proxy_pass http://ip:port;- 請求
http://domain/api/user-> 轉(zhuǎn)發(fā)到http://ip:port/api/user - Nginx 會把完整的路徑拼接到后端地址后。
- 請求
通常后端接口本身包含 /api 前綴時,使用不帶斜杠的方式;如果后端不包含前綴,使用帶斜杠的方式剔除前綴。
6. 進階配置三:性能優(yōu)化(Gzip 與 緩存)
前端構(gòu)建出的 app.js 和 chunk-vendors.js 往往比較大,必須開啟 Gzip 壓縮,并設(shè)置強緩存。
server {
# ... 基礎(chǔ)配置 ...
# --- 開啟 Gzip 壓縮 ---
gzip on;
# 啟用 gzip 壓縮的最小文件,小于設(shè)置值的文件將不會壓縮
gzip_min_length 1k;
# gzip 壓縮級別,1-9,數(shù)字越大壓縮的越好,也越占用CPU時間
gzip_comp_level 6;
# 進行壓縮的文件類型
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
# 是否在http header中添加Vary: Accept-Encoding,建議開啟
gzip_vary on;
# --- 瀏覽器緩存策略 ---
# 1. 針對 index.html:永遠不緩存
# 因為 index.html 引用了帶 hash 的 js/css,如果它被緩存了,發(fā)版后用戶將無法加載新資源
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
# 這里需要重新指定 root,或者利用外層的 root 配置
try_files $uri $uri/ =404;
}
# 2. 針對靜態(tài)資源(JS/CSS/圖片):設(shè)置超長緩存
# Webpack/Vite 打包后的文件名都帶 hash (e.g., app.a1b2c3d4.js)
# 文件內(nèi)容變了 hash 才會變,所以可以放心設(shè)置永久緩存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y; # 緩存一年
add_header Cache-Control "public, no-transform";
access_log off; # 靜態(tài)資源訪問不記錄日志,減少磁盤 I/O
}
# 其他配置...
}
7. 高級部署:Docker 化(推薦)
現(xiàn)在很少直接在物理機上裝 Nginx 了,使用 Docker 部署更加干凈、可移植。
我們將使用 Multi-stage builds (多階段構(gòu)建):在一個 Dockerfile 中完成“構(gòu)建”和“部署”兩步。
7.1 準備 Dockerfile
在項目根目錄下(和 package.json 同級)創(chuàng)建名為 Dockerfile 的文件:
# --- 第一階段:構(gòu)建階段 --- # 使用 Node 鏡像打包 FROM node:18-alpine as build-stage # 設(shè)置工作目錄 WORKDIR /app # 先復(fù)制 package.json 安裝依賴(利用 Docker 緩存層) COPY package*.json ./ RUN npm install --registry=https://registry.npmmirror.com # 復(fù)制源代碼并構(gòu)建 COPY . . RUN npm run build # --- 第二階段:生產(chǎn)環(huán)境 Nginx --- FROM nginx:stable-alpine as production-stage # 復(fù)制第一階段構(gòu)建好的 dist 目錄到 Nginx 默認目錄 # 注意:Vite 默認打包目錄是 dist,如果是 create-react-app 可能是 build COPY --from=build-stage /app/dist /usr/share/nginx/html # 復(fù)制自定義的 Nginx 配置文件(見下文 7.2) COPY nginx.conf /etc/nginx/conf.d/default.conf # 暴露端口 EXPOSE 80 # 啟動 Nginx,daemon off 保證容器不退出 CMD ["nginx", "-g", "daemon off;"]
7.2 準備 nginx.conf
在項目根目錄下創(chuàng)建一個 nginx.conf 文件(這個文件會被 copy 進鏡像):
server {
listen 80;
server_name localhost; # Docker 內(nèi)部通常用 localhost 即可
# 開啟 gzip
gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# 解決 Router History 模式 404
try_files $uri $uri/ /index.html;
}
# 接口代理
location /api/ {
# 注意:在 Docker 中,如果后端也在 Docker 里,這里寫后端容器的服務(wù)名
# 如果后端在宿主機,可以使用 host.docker.internal (Mac/Win) 或 宿主機真實 IP
proxy_pass http://backend-service:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
7.3 構(gòu)建與運行
# 1. 構(gòu)建鏡像 docker build -t my-frontend-app:v1 . # 2. 運行容器 # -d 后臺運行 # -p 80:80 將宿主機的 80 端口映射到容器的 80 端口 docker run -d -p 80:80 --name my-frontend my-frontend-app:v1
8. 完整 Nginx 配置文件模板 (Summary)
為了方便你直接復(fù)制使用,這里提供一個整合了上述所有特性的完整配置文件:
# /etc/nginx/conf.d/frontend.conf
server {
# 1. 端口與域名
listen 80;
server_name www.example.com;
# 2. 根目錄設(shè)置
root /usr/share/nginx/html/dist;
index index.html;
# 3. 日志設(shè)置
access_log /var/log/nginx/host.access.log main;
error_log /var/log/nginx/host.error.log warn;
# 4. Gzip 壓縮優(yōu)化
gzip on;
gzip_static on; # 如果存在 .gz 文件直接使用,不現(xiàn)場壓縮
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
# 5. 主應(yīng)用路由 (SPA 支持)
location / {
# 解決單頁應(yīng)用 History 模式刷新 404 問題
try_files $uri $uri/ /index.html;
# 針對 index.html 設(shè)置協(xié)商緩存或不緩存
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# 6. 靜態(tài)資源長緩存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
access_log off;
}
# 7. 反向代理接口
location /api/ {
# 假設(shè)后端接口地址
proxy_pass http://127.0.0.1:8080/api/;
# 傳遞真實 IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 支持 WebSocket (如果需要)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 8. 錯誤頁面處理
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
9. 常見報錯排查 (Troubleshooting)
Q1: 訪問頁面出現(xiàn)403 Forbidden
原因:Nginx 啟動用戶(通常是 nginx 或 nobody)沒有權(quán)限讀取你的 dist 目錄。
解決:
- 修改
nginx.conf頭部,將user nginx;改為user root;(簡單粗暴,但不安全)。 - 或者賦予目錄權(quán)限:
chmod -R 755 /usr/share/nginx/html/dist。
Q2: 訪問頁面白屏,控制臺報錯Uncaught SyntaxError: Unexpected token <
原因:這通常是因為 Nginx 沒找到 JS/CSS 文件,觸發(fā)了 try_files 回退到了 index.html。瀏覽器把 index.html 的 HTML 內(nèi)容當成了 JS 解析,所以報錯。
排查:
- 檢查
build時的publicPath或base設(shè)置。如果項目部署在子路徑(如/app/),前端構(gòu)建配置必須設(shè)置對應(yīng)的 base。 - 檢查 Nginx
root路徑是否正確。
Q3: 反向代理接口報 502 Bad Gateway
原因:Nginx 連不上后端服務(wù)。
排查:
- 后端服務(wù)沒啟動。
- 防火墻攔截了端口。
- 如果用了 Docker,檢查容器網(wǎng)絡(luò)(Docker 容器內(nèi)無法通過 127.0.0.1 訪問宿主機服務(wù))。
10. 總結(jié)
Nginx 掛載前端包的核心步驟可以概括為:
- Build:生成
dist靜態(tài)資源。 - Root:配置 Nginx 指向該目錄。
- Try_files:配置兜底策略解決 SPA 路由問題。
- Proxy:配置反向代理打通后端 API。
掌握了這份指南,無論是簡單的個人博客還是復(fù)雜的企業(yè)級中臺系統(tǒng),你都能從容應(yīng)對其前端部署工作。希望這份翔實的教程對你有所幫助!
到此這篇關(guān)于Nginx部署前端項目實戰(zhàn)指南及常見錯誤的文章就介紹到這了,更多相關(guān)Nginx部署前端項目內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx使用nginx-rtmp-module模塊實現(xiàn)直播間功能
做的過程出現(xiàn)很多問題,環(huán)境其實就需要nginx就可以,然后就是在播放的問題,m3u8的格式,mac直接訪問就支持,蘋果系統(tǒng)原生H5支持m3u8,還有就是手機直接訪問也支持!但是其他其他系統(tǒng)PC端不支持,嘗試了好多都不行,最后終于找到了一個支持m3u8格式H5播放2017-10-10
Nginx強制跳轉(zhuǎn)Https(Http訪問跳轉(zhuǎn)Https)
這篇文章主要為大家介紹了Http訪問強制跳轉(zhuǎn)到Https的幾種方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10

