作者:UCloud云通信技術(shù)團(tuán)隊(duì)
https://juejin.cn/post/7295926959842033699
Nginx是在前端服務(wù)部署時(shí)是很重要的一部分,也是部署的基礎(chǔ),學(xué)會(huì)了通過Nginx部署前端資源,才能繼續(xù)后續(xù)的一系列進(jìn)階。
一、了解一點(diǎn)簡(jiǎn)單的Nginx知識(shí)
本節(jié)內(nèi)容作為基礎(chǔ)知識(shí),如果熟悉Nginx可以略過,如果不熟悉可以實(shí)際操作一下。
現(xiàn)在服務(wù)器安裝Nginx很簡(jiǎn)單,一般只需要兩行命令即可,安裝完成后,啟動(dòng)服務(wù)。
# 安裝nginx
yum install -y nginx
# 啟動(dòng)nginx
systemctl start nginx
# 查看nginx運(yùn)行狀態(tài)
systemctl status nginx
當(dāng)我們看到下圖,說明你的Nginx運(yùn)行正常,此時(shí)Nginx會(huì)啟動(dòng)服務(wù),默認(rèn)80端口。此時(shí)如果我們的服務(wù)器外網(wǎng)防火墻80
端口開啟,那么訪問外網(wǎng)IP,就能看到Nginx啟動(dòng)的服務(wù)
Nginx的配置文件,一般位于/etc/nginx
目錄下,具體內(nèi)容如下:
我們基本只需要關(guān)注文件nginx.conf
和conf.d
目錄,下面是一份nginx.conf
配置文件,不懂也不要怕,基本都不需要改動(dòng),默認(rèn)80服務(wù)已經(jīng)開啟了。
user nginx; # nginx進(jìn)行運(yùn)行的用戶
error_log /var/log/nginx/error.log; # 錯(cuò)誤日志
http {
log_format main ...; # nginx日志格式
access_log /var/log/nginx/access.log main; # 日志位置
# 引入的nginx配置文件,可以將server放在該目錄下,方便管理
include /etc/nginx/conf.d/*.conf;
# 一個(gè)nginx服務(wù)一個(gè)server
server {
listen 80; # 服務(wù)啟動(dòng)的端口
server_name _; # 服務(wù)域名或IP
root /usr/share/nginx/html; # 服務(wù)指向的文件地址
error_page 404 /404.html; # 找不到資源重定向到404頁面
location = /40x.html {};
error_page 500 502 503 504 /50x.html; # 系統(tǒng)錯(cuò)誤重定向50x頁面
location = /50x.html {};
}
# server {
# listen 443; # 支持https協(xié)議
# server_name _;
# root /usr/share/nginx/html;
# ...
# }
}
我們可以看到該文件分成了多層
- 第二層:log_format、access_log、include、server
在http下可以有多個(gè)Server
,啟動(dòng)多個(gè)服務(wù),但如果都寫在一個(gè)文件里面,文件就越來越大了,那么為了便于管理多個(gè)服務(wù),我們要對(duì)nginx.conf
進(jìn)行拆分。
conf.d目錄下一般是空的,我們新建文件 web.conf或者任意命名的以.conf結(jié)尾的文件即可被Nginx使用,內(nèi)容為:
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
error_page 404 /404.html;
location = /40x.html {};
error_page 500 502 503 504 /50x.html;
location = /50x.html {};
}
由于這里使用了80端口,之前nginx.conf文件server中l(wèi)isten為80的可以刪除了。
此時(shí)nginx.conf中的文件內(nèi)容為:
user nginx; # nginx進(jìn)行運(yùn)行的用戶
error_log /var/log/nginx/error.log; # 錯(cuò)誤日志
http {
log_format main ...; # nginx日志格式
access_log /var/log/nginx/access.log main; # 日志位置
# 引入的nginx配置文件,可以將server放在該目錄下,方便管理
include /etc/nginx/conf.d/*.conf;
}
include /etc/nginx/conf.d/*.conf;
我們看到這一行語句發(fā)現(xiàn),include幫助我們引用conf.d下以.conf結(jié)尾的配置文件。
完成后執(zhí)行nginx指令
# 檢查nginx配置文件是否正確,如果錯(cuò)誤會(huì)提示具體的錯(cuò)誤信息
nginx -t
# 重新啟動(dòng)nginx服務(wù)
nginx -s reload
觀察日志,此時(shí)發(fā)現(xiàn)Nginx就重新啟動(dòng)了,讀取的是新的配置文件。
其他操作nginx的指令
nginx -s stop
nginx -s start
二、啟動(dòng)一個(gè)簡(jiǎn)單的Nginx服務(wù)
- 一臺(tái)服務(wù)器或PC,安裝并啟動(dòng)Nginx服務(wù)
/data/web
兩個(gè)html文件index.html
, about.html
1、index.html
或about.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>nginx</title>
</head>
<body>
通過nginx部署的第一個(gè)服務(wù)
</body>
</html>
2、修改/etc/nginx/conf.d/web.conf
server {
listen 80;
server_name localhost;
root /data/web;
index index.html;
}
執(zhí)行nginx -t
確認(rèn)配置文件修改沒問題,再執(zhí)行nginx -s reload
重啟Nginx,此時(shí)我們?cè)L問外網(wǎng)IP(默認(rèn)80端口,下面默認(rèn)都是訪問80端口),可以看到
這樣我們的靜態(tài)資源文件就部署好了,通過url訪問資源:
三、部署單頁面應(yīng)用
我們快速創(chuàng)建一個(gè)CRA單頁面應(yīng)用,修改App.js文件,這里使用react-router-dom@6
1、Hash模式
import { HashRouter, Routes, Route, Link } from "react-router-dom";
import './App.css';
function App() {
return (
<div className="App">
<HashRouter basename="/">
<div style={{marginBottom: 20}}>
<Link style={{marginRight: 20}} to="/">Home</Link>
<Link to="/about">About</Link>
</div>
<Routes>
<Route path="/" element={<div>home</div>}></Route>
<Route path="/about" element={<div>about</div>} />
</Routes>
</HashRouter>
</div>
);
}
export default App;
我們執(zhí)行yarn build
,然后將build
目錄下的文件遷移到/data/web
下,再訪問服務(wù)器IP,發(fā)現(xiàn)訪問正常,路由切換也沒有問題,即部署成功。
2、History模式
import {
BrowserRouter,
...
} from "react-router-dom";
將Hash模式中的代碼修改為BrowserRouter,運(yùn)行本地項(xiàng)目,路由切換正常,該路由是History模式
同樣執(zhí)行yarn build
生成build
目錄,將該目錄下的文件遷移到上一步服務(wù)器的目錄/data/web下,然后訪問外網(wǎng)IP,發(fā)現(xiàn)渲染效果和上圖一樣,但是當(dāng)我們點(diǎn)擊About頁面,然后刷新瀏覽器發(fā)現(xiàn),出現(xiàn)了404。
先說解決辦法,然后解釋下原因,修改Nginx配置web.conf
增加一行try_files配置,當(dāng)請(qǐng)求的地址找不到時(shí),重新指向index.html文件
server {
listen 80;
server_name localhost;
root /data/www/;
location / {
try_files $uri $uri/ /index.html;
index index.html;
}
}
重啟nginx nginx -t
、nginx -s reload
再次刷新頁面,發(fā)現(xiàn)頁面訪問正常了,切換也沒有問題。
3、為什么hash模式不會(huì)出現(xiàn)404,而history模式會(huì)出現(xiàn)404?
了解下這兩種模式的區(qū)別就知道答案了
1)Hash模式
在hash路由模式下,URL中的Hash值(#后面的部分)用來表示應(yīng)用的狀態(tài)或路由信息。當(dāng)用戶切換路由時(shí),只有Hash部分發(fā)生變化,并沒有向服務(wù)器發(fā)出請(qǐng)求,就做到了瀏覽器對(duì)于頁面路由的管理。
- Hash模式下,URL和路由路徑由#號(hào)分隔:
http://example.com/#/about?query=abc
- 當(dāng)
#
后面的路徑發(fā)生變化時(shí),會(huì)觸發(fā)瀏覽器的hashchange事件,通過hashchange事件監(jiān)聽到路由路徑的變化,從而導(dǎo)航到不同的路由頁面。 - Hash模式
#
后面的路徑并不會(huì)作為URL出現(xiàn)在網(wǎng)絡(luò)請(qǐng)求中。例如對(duì)于輸入的example.com/#/about[1] ,實(shí)際上請(qǐng)求的URL是example.com/[2] ,所以不管輸入的Hash路由路徑是什么,實(shí)際網(wǎng)絡(luò)請(qǐng)求的都是主域名或IP:Port
2)History模式
History路由模式下,調(diào)用瀏覽器HTML5中history
API來管理導(dǎo)航。URL和路徑是連接在一起的,路由的路徑包含在請(qǐng)求的URL里面,路由路徑作為URL的一部分一起發(fā)送。
- History模式下,URL路由格式為:
http://example.com/about&query=abc
- 當(dāng)我們向服務(wù)器發(fā)出請(qǐng)求時(shí),服務(wù)器會(huì)請(qǐng)求對(duì)應(yīng)的路徑的資源
綜上,當(dāng)我們打開入口文件index.html的路徑時(shí),切換url此時(shí)是本地路由,訪問正常,但是當(dāng)我們處于非入口頁面時(shí),刷新瀏覽器,此時(shí)發(fā)出請(qǐng)求,由于服務(wù)器就找不到資源路徑了,變成了404。
而對(duì)于Hash模式來說,總是請(qǐng)求的根路徑,所以不會(huì)出現(xiàn)這種情況。
四、配置反向代理、負(fù)載均衡
1、反向代理
反向代理的用途很多,這里我們看一個(gè)常用的,代理請(qǐng)求的接口。我們?cè)诎l(fā)布時(shí)前端的域名和后端api服務(wù)的域名經(jīng)常不一致,此時(shí)就可以使用Nginx配置反向代理來解決這個(gè)問題。
server {
location /api {
proxy_pass http://backend1.example.com;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
代理的時(shí)候要注意添加必要的參數(shù),幫助后端獲取一些客戶端的請(qǐng)求數(shù)據(jù)
proxy_set_header Host $host;
:客戶端請(qǐng)求的主機(jī)名(Host),不加的話,后端無法獲取主機(jī)名信息proxy_set_header X-Real-IP $remote_addr;
:用戶的真實(shí)IP(X-Real-IP),如果不設(shè)置,后端只能拿到代理服務(wù)器的IPproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
代理鏈路,如果用戶中間經(jīng)過了多個(gè)代理服務(wù)器,如果不加這個(gè)參數(shù),那么后端服務(wù)將無法獲取用戶的真實(shí)來源
2、負(fù)載均衡
Nginx可以作為負(fù)載均衡服務(wù)器使用,通過配置upstream來分發(fā)流量,同時(shí)可以配置一些參數(shù):
- ip_hash:配置始終將ip的請(qǐng)求始終轉(zhuǎn)發(fā)到同一臺(tái)后端服務(wù)器。
- max_fails: 將某個(gè)后臺(tái)服務(wù)標(biāo)記為不可用之前,允許請(qǐng)求失敗的次數(shù)
- backup:標(biāo)記當(dāng)前服務(wù)為備用服務(wù)
upstream api {
ip_hash;
server backend1.example.com;
server backend2.example.com;
# server backend1.example.com weight=5;
}
server {
location /api {
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
五、配置nginx日志
Nginx日志也是很重要的一個(gè)內(nèi)容,在我們請(qǐng)求資源出現(xiàn)問題時(shí),要排查請(qǐng)求的資源是否到達(dá)Nginx,而且請(qǐng)求日志可以記錄很多有用的信息。
log_format gzip '$remote_addr - $remote_user [$time_local] '
: '"$request" $status $bytes_sent '
: '"$http_referer" "$http_user_agent" "$gzip_ratio"';
access_log /var/logs/nginx-access.log gzip buffer=32k;
nginx日志主要涉及access_log
,log_format
log_format
: 日志格式,通過nginx內(nèi)置的變量來讀取和排列,通常默認(rèn)即可access_log
: 日志輸出的地址、是否壓縮、buffer是否當(dāng)日志大于32k后吸入磁盤
六、其他常用配置
1、配置Gzip壓縮
作為前端性能優(yōu)化的一種方式,Gzip是簡(jiǎn)單且有效的,盡管目前前端對(duì)于靜態(tài)資源會(huì)進(jìn)行壓縮,但Gzip依然可以在網(wǎng)絡(luò)傳輸過程中對(duì)文件進(jìn)行壓縮
下面這些字段可以放在http、server、location
指令模塊
http {
# 開啟關(guān)閉
gzip on;
# 壓縮的文件類型
gzip_types text/plain text/css application/javascript;
# 過小的文件沒必要壓縮
gzip_min_length 1000; # 單位Byte
gzip_comp_level 5; # 壓縮比,默認(rèn)1,范圍時(shí)1-9,值越大壓縮比最大,但處理最慢,所以設(shè)置5左右比較合理。
}
2、配置請(qǐng)求頭
允許客戶端請(qǐng)求在http請(qǐng)求中添加以下劃線格式命名的參數(shù)
該字段可以放在http
指令模塊
http {
underscores_in_headers on;
}
```
**允許客戶端上傳文件最大不超過1M,在開發(fā)上傳接口時(shí)一定要注意,否則導(dǎo)致上傳失敗**
該字段可以放在`http、server、location`指令模塊
http {
client_max_body_size 1m;
}
### 3、瀏覽器緩存配置
**緩存也是前端優(yōu)化的一個(gè)重點(diǎn),合理的緩存可以提高用戶訪問速度**
該字段可以放在`http、server、location`指令模塊
配置瀏覽器緩存的有三個(gè)地方
#### 1)后端服務(wù),配置請(qǐng)求頭
后端根據(jù)語言不同,配置關(guān)鍵字段即可
#### 2)代理服務(wù)器(Nginx)配置緩存請(qǐng)求頭
```nginx
location /static {
# /static匹配到的資源有效期設(shè)置為1d;
expires 1d;
# /設(shè)置資源有效期為一周;
# expires max-age=604800;
# 設(shè)置瀏覽器可以被緩存,設(shè)置7天后資源過期
add_header Cache-Control "public, max-age=604800";
# 阻止瀏覽器緩存動(dòng)態(tài)內(nèi)容
# add_header Cache-Control "no-cache, no-store, must-revalidate";
# 禁用瀏覽器緩存
# add_header Cache-Control "no-store, private, max-age=0";
}
我們發(fā)現(xiàn)響應(yīng)頭的過期時(shí)間更新了
?
3)在前端資源中通過meta聲明緩存信息
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Expires" content="0">
4、跨域處理
通過反向代理,已經(jīng)處理了請(qǐng)求域名和端口不一致的跨域問題,但有局限性。Nginx有專門方法配置請(qǐng)求資源的跨域
該字段可以放在server、location
指令模塊,通過配置頭部字段,做跨域處理
server {
location / {
# 允許所有來源的跨域請(qǐng)求
add_header Access-Control-Allow-Origin *;
# 允許特定的HTTP方法(GET、POST等)
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
# 允許特定的HTTP請(qǐng)求頭字段
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
# 響應(yīng)預(yù)檢請(qǐng)求的最大時(shí)間
add_header Access-Control-Max-Age 3600;
# 允許攜帶身份憑證(如Cookie)
add_header Access-Control-Allow-Credentials true;
# 處理 OPTIONS 預(yù)檢請(qǐng)求
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
}
}
七、總結(jié)
以上就是Nginx常用的內(nèi)容,也是在工作中遇到的經(jīng)常遇到的一些情況,足夠來部署前端服務(wù)了。
該文章在 2024/10/24 9:24:39 編輯過