Nginx-包教包會-入門
前言
Nginx
作為 web 伺服器
以低記憶體,高擴充套件,並且輕鬆單機支援 1-3w
(據說可以單機 10w,但沒有看到具體的機器配置)的併發連結的特性廣受開發人員的青睞。
推薦在 linux
系統上使用 Nginx
,這會充分利用 linux
的特性,效能比在 windows
上會更好。
本文主要內容:
- Nginx 簡單配置
- root 和 alias 的區別
- location 的優先順序及驗證
- Nginx 內建變數介紹
- if
- rewrite 轉發
- try_files
- 配置 gzip
- 協商快取和強快取的介紹和配置
後續章節,我會使用 ab
壓測來一步一步最佳化 Nginx
的配置,Nginx 知道原理,懂得常用配置即可。有的效能最佳化需要了解 linux 核心
、http
、tcp
相關的東西,如果你不想了解,可以記錄一份自己的配置即可,不必糾結為什麼。
本文內容在 nginx 1.16.1
上測試,Centos 7
4核 8g 記憶體的虛擬機器。
Nginx 安裝
Nginx 安裝步驟
根據 配置 yum
源,提高下載速度。
配置我們常用軟體的包,Nginx
也在其中。
# 執行一下命令,更新 yum 源
yum clean all
yum makecache
重新整理 yum
倉庫資訊之後,執行以下命令就可以找到 nginx
yum list | grep nginx
安裝 nginx
sudo yum install nginx
配置 nginx
開機啟動
sudo systemctl enable nginx
啟動 nginx
sudo systemctl start nginx
檢查 nginx
是否啟動
sudo systemctl status nginx
如果想檢視 nginx
包都安裝了哪些檔案,可以使用
rpm -qvl nginx
Nginx 命令
# 強制立即關閉,不建議做
nginx -s stop
# 正常關閉,會處理已經接到的請求,但不會接受新的請求
nginx -s quit
# 重新載入配置檔案
nginx -s reload
# 重新開啟日誌檔案
nginx -s reopen
# 檢查配置檔案是否有誤
nginx -t
# 檢查配置檔案是否有誤,會將配置檔案內容列印
nginx -T
# 檢視 nginx 版本
nginx -v
# 檢視 nginx 版本和編譯配置致殘
nginx -V
系統開啟、關閉、重啟、檢視 nginx 命令
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl restart nginx
sudo systemctl stop nginx
sudo systemctl status nginx
Nginx 簡單配置
Nginx 介紹
部署的 Nginx
使用一個 master
程式管理多個 worker
程式。master
程式不處理請求,提供管理服務,包括啟動、停止、過載配置檔案等服務,通常以 root
使用者啟動, worker
程式進行請求的處理,一般用非管理員賬戶啟用,worker
程式數量和 cpu 核心設定一直,降低程式切換帶來的 cpu
切換。
http
上下文中的配置是我們重點需要知道的,其餘的瞭解會配置即可。
Server 配置
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80 ;
server_name _;
root /usr/share/nginx/html;
location / {
}
}
}
Server
既配置一個服務。
listen 80
用於配置監聽 80
埠的服務。
root
指定靜態資源存放的位置。
location 進行資源匹配。location / {}
匹配所有的資源。
listen
和 server_name
配置
匹配規則:
- 先匹配
listen
再匹配server_name
-
server_name
匹配請求頭中的Host
- 當都沒有匹配成功,由配置
default_server
的處理 - 以上都沒有匹配成功,由第一個配置處理
server {
listen 9099 default_server;
server_name "localhost";
location / {
return 200 "server_name 為 localhost";
}
}
server {
listen 9099;
server_name 127.0.0.1;
location / {
return 200 "server_name 為 127.0.0.1";
}
}
server {
listen 9099;
server_name "localhost77";
location / {
return 200 "server_name 為 localhost77";
}
}
在 Postman
中設定請求頭 Host
模擬訪問。
Host:
127.0.0.1
返回 server_name 為 127.0.0.1
Host:
localhost
返回 server_name 為 localhost
Host:
localhost77
返回 server_name 為 localhost77
Host:
localhost779
返回 server_name 為 localhost
再新增一個配置
server {
listen localhost:9099 default_server;
server_name "localhost";
location / {
return 200 "server_name 為 localhost:9099";
}
}
當 listen
訪問 localhost:9099
的時候,返回 server_name 為 localhost:9099
,因為只有這一個匹配上了。
如果想禁止沒有 Host
請求頭的訪問。
server {
listen 80;
server_name "";
# 表示 nginx 會關閉連線
return 444;
}
return
配置
return
用於定義返回的狀態碼,或者內容。
介紹 return
主要是為了好描述 location
配置
- | 說明 |
---|---|
語法 | return code [text]; return code URL; return URL ; |
預設 | - |
上下文 | server、location、if |
code
為狀態碼。text
為字串。
location /a {
default_type application/json;
return 200 "訪問 9088/a";
}
# 重定向
location = /b {
return 301 http://www.baidu.com;
}
location
配置
location
用於匹配資源。
數字越小,優先順序越高。
規則符號 | 描述 | 優先順序 |
---|---|---|
location = /a{} | 精準完全匹配,匹配到之後 | 1 |
location ^~ /a{} | 字首匹配,匹配到之後 | 2 |
location ~ /a.*{} | 正則匹配,區分大小寫,檢查到之後,還會檢查有沒有優先順序跟高的 | 3 |
location ~* /a.* | 正則匹配,不區分字母大小寫,檢查到之後,還會檢查有沒有優先順序跟高的 | 4 |
location /a {} | 也表示字首匹配,但是優先順序低於 正則匹配。 /a 和 ^~/a 會衝突,報錯 | 5 |
location / {} | 任何沒有匹配成功的,都會匹配這裡處理 | 6 |
server {
listen 9088 default_server;
server_name _ ;
location = /a {
default_type application/json;
return 200 "= /a,優先順序第一";
}
location ^~ /a {
default_type application/json;
return 200 "^~ /a 匹配 /a 開頭的路徑,優先順序第二";
}
location ~ /a.* {
default_type application/json;
return 200 " /a.* 匹配 /a...路徑,優先順序第三";
}
location ~* /a.* {
default_type application/json;
return 200 "~* /a.* 匹配 /a...路徑,優先順序第四";
}
# /a 會和 ^~ /a 衝突
location /a/ {
default_type application/json;
return 200 "/a/ 匹配 /a/...路徑,優先順序第五";
}
}
訪問 ,依次註釋優先順序較高的,可以驗證這個規律。
還有一類特殊的 location
用於配置跳轉的,以 @
開頭
location @pass {
}
add_header 新增響應頭
- | 說明 |
---|---|
語法 | add_header name value [always]; |
預設 | - |
上下文 | http、server、location、location 中的 if |
如果響應程式碼等於 200、201、204、206、301、302、303、304、307或 308,則將指定的欄位新增到響應報頭中。
加上 always
不管什麼狀態碼都加上。
location ~ /a.* {
default_type application/json;
add_header test1 "asdfasdf" always;
return 200 " /a.* 匹配 /a...路徑,優先順序第三";
}
error_page
- | 說明 |
---|---|
語法 | error_page code …[=[response code]] uri; |
預設 | - |
上下文 | http、server、location、location 中的 if |
配置錯誤狀態碼跳轉頁面。
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
以上不會改變響應狀態碼。
# 改變響應狀態嗎。
error_page 404 =200 /404.html;
server {
location / {
error_page 404 = @ops-coffee;
}
location @ops-coffee {
rewrite .* / permanent;
}
}
root 和 alias 的區別
alias
理解為:路徑替換,location 以 /
結尾,alias 必須以 /
結尾。嚴格匹配。alias
替換掉 location
路徑。
# /bieming/ 替換 /usr/local/var/www/alias2/
# 訪問 /bieming/1.jpg 去尋找 /usr/local/var/www/alias2/1.jpg
location /bieming/ {
alias /usr/local/var/www/alias2/;
}
root
理解為:root 路徑加上 + location
路徑。會將兩個或更多個 /
壓縮成一個。
# 當 location 和 root 路徑的最後一部分匹配時,更好的方式是使用 root
## 以下配置都可以。
# 訪問 /data2/1.jpg 去尋找 /usr/local/var/www/data2/1.jpg
location /data2/ {
root /usr/local/var/www;
}
location /data2/ {
root /usr/local/var/www/;
}
location /data2 {
root /usr/local/var/www;
}
location /data2 {
root /usr/local/var/www/;
}
location /data2/ {
root /usr/local/var/www////;
}
內建變數
透過內建變數,我們可以透過判斷請求頭、query string
等值來轉發或者拒絕訪問。
$arg_name
獲取請求引數
獲取請求query string
中的 name
引數。
location /arg/ {
default_type application/json;
return 200 "$arg_q1";
}
/arg/a?q1=334
返回的內容為 334
。
$args
獲取請求 query_string
引數
location /arg/ {
default_type application/json;
return 200 "$arg_q1 _ $args";
}
瀏覽器訪問 /arg/a?q1=3334&aa=2&bb=33
返回的內容為 3334 _ q1=3334&aa=2&bb=33
$cookie_name
獲取cookie的值
獲取請求中的名稱為 name
的 cookie。
$http_name
獲取請求頭
name
為請求頭中的欄位名稱,請求頭名稱全部小寫,並將破折號-
替換為下劃線 _
$http_user_agent
獲取請求頭中的 User-Agent
欄位。
$uri
獲取請求路徑中的 path
path
為埠後面的路徑,不包括 query string
。最佳化之後的路徑,特殊字元轉譯及 /
壓縮。
中的
path
為 /arg/a
$host
獲取請求的 ip
首先會獲取請求頭 Host
,如果沒有請求頭中沒有 Host
請求頭,那麼獲取的是 url
中的 ip
。
$request_uri
獲取 path
和 query string
訪問
$request_uri
為/arg/a/?q1=q1canshu&bb=2323
$scheme
獲取請求協議
值為 http
或 https
$request_method
獲取請求方法
獲得的值字母全大寫。GET,POST,DELETE,PUT 等
其他變數
- | 描述 |
---|---|
$content_length | 獲取 Content-Length 請求頭欄位。 |
$content_type | 獲取 Content-Type 請求頭欄位 |
$https | 如果連線以 SSL 模式執行,則為 on ,否則為空字串 |
$is_args | 如果請求行有引數則為 ? ,否則為空字串 |
$pid | 獲取處理當前請求的 worker pid |
$nginx_version | 獲取 nginx 的版本 |
if
- | 說明 |
---|---|
語法 | if (condition ){} |
預設 | - |
上下文 | server、location |
指定的 condition 求值之後,如果為 true ,則執行在大括號內指定的該模組的指令,並在 if 指令內為該請求分配配置。 if 指令內的配置繼承自上一層的配置級別。
condition 可以是以下任何一種:
-
變數名,如果變數的值為空字串或 0 ,則為 false
-
使用 = 和 != 運算子比較變數和字串
-
使用 ~ (區分大小寫的匹配)和 ~* (不區分大小寫的匹配)運算子,變數將與正規表示式進行匹配。正規表示式可以包含可供以後在
$1
…$9
變數中重用的捕獲。 -
反運算子 !~ 和 !~* 也可用。如果正規表示式包含 } 或 ; 字元,則整個表示式應使用單引號 或雙引號包圍起來。
-
使用 -f 和 !-f 運算子檢查檔案是否存在
-
使用 -d 和 !-d 運算子檢查目錄是否存在
-
使用 -e 和 !-e 運算子檢查檔案、目錄或符號連結是否存在
-
使用 -x 和 !-x 運算子檢查是否為可執行檔案
if
與小括號之間需要有空格
location = /a {
default_type application/json;
if ($request_uri ~* "/(a).*") {
return 200 "正規表示式捕獲的值:$1";
}
return 200 "= /a,優先順序第一";
}
rewrite
- | 說明 |
---|---|
語法 | rewrite regex replacement [flag]; |
預設 | - |
上下文 | server、location、if |
flag
可選引數:
- last
停止匹配,傳送一個新的請求去匹配 location
。
- break
停止匹配,在當前 location
去搜尋資源。
- redirect
臨時重定向。返回狀態碼 302
。
- permanent
永久重定向。返回狀態碼 301
。
指定的 regex
能匹配,uri 將根據 replacement
來處理。
驗證 break 和 last
以下三張圖片都存在,但是內容不一樣。
/Users/zhangpanqin/stduy_app/break2/test/1.jpg
/Users/zhangpanqin/stduy_app/last2/test/1.jpg
/Users/zhangpanqin/stduy_app/test/1.jpg
location /break2 {
root /Users/zhangpanqin/stduy_app/break2;
rewrite /break2/(.*) /test/$1 break;
}
location /last2 {
root /Users/zhangpanqin/stduy_app/last2;
rewrite /last2/(.*) /test/$1 last;
}
location /test/ {
root /Users/zhangpanqin/stduy_app;
}
當訪問 /break2/1.jpg
實際匹配第一個 location
,然後在當前上下文處理 。
/break2/1.jpg
被替換為 /test/1.jpg
來處理了,然後和 root
指定的路徑相結合,返回 /Users/zhangpanqin/stduy_app/break2/test/1.jpg
資料。
當訪問 /last2/1.jpg
,uri 被替換為 /test/1.jpg
去匹配新的 location 進行處理。
返回 /Users/zhangpanqin/stduy_app/test/1.jpg
的內容。
驗證 redirect
和 permanent
location /redirect2 {
rewrite ^/redirect2 http://www.baidu.com redirect;
}
location /permanent2 {
rewrite ^/permanent2 http://www.baidu.com permanent;
}
二者匹配成功之後,都會改變瀏覽器位址列地址。瀏覽器根據響應頭 Location
跳轉對應地址。
二者的區別在於,永久重定向 (permanent
),瀏覽器會儲存記錄,當再訪問 而不會詢問
nginx
直接跳轉。
臨時重定向,瀏覽器每次都要詢問 nginx
需要跳轉到哪裡。可以關閉 nginx
就知道驗證結果了。
try_files
- | 說明 |
---|---|
語法 | try_files file … uri; try_files file … =code ; |
預設 | - |
上下文 | server、location |
以指定順序檢查檔案是否存在,並使用第一個找到的檔案進行請求處理。如果找不到內容內部轉發到最後一個引數 uri
。檔案位置為 root
+ file
。
location /try/ {
root /usr/local/var/www/data2/data2/;
try_files $uri $uri/ @pass2;
}
location @pass2 {
default_type application/json ;
return 200 "沒到到頁面代理的資料" ;
}
訪問 /try/1.jpg
時,$uri
為 /try/1.jpg
。
root
+ $uri
為 /usr/local/var/www/data2/data2/try/1.jpg
找到返回,沒有找到繼續匹配返回。都沒有匹配內部轉發至 @pass2
。
如想驗證跳轉使用 /try/test
之類的,不要使用字尾名,因為使用字尾名的話,瀏覽器會返回content-type
,導致內容與解析不一致,圖片出不來。
配置 gzip
# 開啟 gzip
gzip on;
# 在響應頭中增加,Vary: Accept-Encoding
gzip_vary on;
# gzip壓縮級別1-9,數字越大壓縮效果越好,壓縮所用時間也就越長,佔用CPU越高
gzip_comp_level 6;
# 申請記憶體時大小,如果原始檔 9k,超過了 8K,那會申請 16*8K。
gzip_buffers 16 8k;
gzip_min_length 2K;
gzip_proxied any;
gzip_disable "msie6";
gzip_http_version 1.1;
# 文字(js、text、css、xml、json)壓縮比較好,圖片已經進行過壓縮,在壓縮,效果不是很明顯,還浪費 cpu
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss application/rss+xml application/atom+xml image/svg+xml;
gzip 壓縮對文字效果比較好,推薦只對文字之類的壓縮。
配置快取
為了減輕伺服器壓力,節省頻寬,可以配置快取。
memory cache
:它是將資原始檔快取到記憶體中,快取有效直接從記憶體載入。
disk cache
: 它是將資原始檔快取到硬碟中,快取有效直接從硬碟中載入。
先從 memory cache
找,找不到從 disk cache
找,再找不到,請求網路資源。
快取分為 協商快取
和 強快取
。
協商快取
每次都要去伺服器詢問快取是否過期,沒有過期使用本地的快取。
強快取
會有快取過期時間,在有效期內不會去服務端校驗快取,直接使用本地快取。
現在的 webpack
可以根據檔案內容的 hash
生產類似 app.asdfa21342.js
這樣的檔案。其實就是想使用強快取,當網站更新,新的頁面會解析載入不一樣的資源,從而降低快取校驗對伺服器效能的損耗。
協商快取
協商快取有:ETag/if-None-Match
和 Last-Modified/if-Modify-Since
兩種。
http 協議規定,當這兩種響應頭都存在的時候,必須都要滿足,才能使用快取。
ETag/if-None-Match
- | 說明 |
---|---|
語法 | etag on|off; |
預設 | etag on; |
上下文 | http、server、location |
nginx
有個 etag 配置屬性,會給每個靜態資源生成 Etag
響應頭,值為檔案內容 hash
。
當瀏覽器第一次訪問資源的時候,返回的響應頭中攜帶 Etag
。
後續的正常訪問(不強制重新整理快取)相同的資源,都會帶上請求頭 if-None-Match
,值為 Etag
去 nginx
校驗是否一樣,一樣說明快取沒有過期,返回狀態碼 304
,直接訪問瀏覽器中的快取,否則從瀏覽器返回資源,返回狀態碼 200。
Last-Modified/if-Modify-Since
- | 說明 |
---|---|
語法 | if_modified_since off|exact|before; |
預設 | if_modified_since exact; |
上下文 | http、server、location |
指定如何比較檔案的修改時間與請求頭 If-Modified-Since 進行比較:
- off
忽略 If-Modified-Since 請求頭欄位(0.7.34)
- exact
完全匹配
- before
資源的修改時間小於或等於 If-Modified-Since 請求頭欄位中的時間
瀏覽器第一次訪問一個資源的時候,響應頭 Last-Modified
返回,標識檔案的最後修改時間。
當瀏覽器再次正常訪問(不強制重新整理資源)相同資源,請求頭會加上 If-Modified-Since
,該值為之前返回的 Last-Modified
。nginx
收到 If-Modified-Since
後,根據配置 if_modified_since
屬性比較資源的最後修改時間(Last-Modified
)和該值If-Modified-Since
進行比較,匹配成功,則命中快取,返回304,否則返回 資源,狀態碼為 200,並更新快取時間。
強制快取
Expires
Expires
是 http1.0
的規範,它的值是一個絕對時間的GMT格式的時間字串。這個時間代表的該資源的失效時間,如果在該時間之前請求的話,則都是從快取裡面讀取的。如果服務端和客戶端時區不一致會導致判斷不準確。
Cache-Control
Cache-Control
是 http1.1
的規範,它是利用該欄位 max-age
值進行判斷的。該值是一個相對時間,比如 Cache-Control: max-age=3600
代表該資源的有效期是3600秒。除了該欄位外,我們還有如下欄位可以設定:
no-cache: 需要進行協商快取,傳送請求到伺服器確認是否使用快取。
**no-store:**禁止使用快取,每一次都要重新請求資料。
**public:**可以被所有的使用者快取,包括終端使用者和 CDN 等中間代理伺服器。
**private:**只能被終端使用者的瀏覽器快取,不允許 CDN 等中繼快取伺服器對其快取。
配置快取
location ~* .(css|js|png|jpg|jpeg|gif|gz|svg|mp4|mp3|ogg|ogv|webm|htc|xml|woff)$ {
# 關閉訪問日誌記錄
access_log off;
# 強快取,時間為一年,瀏覽器和 cdn 中介軟體可以快取
add_header Cache-Control "max-age=31536000";
}
推薦資料
本文由 創作。 可自由轉載、引用,但需署名作者且註明文章出處。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3486/viewspace-2825136/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 包教包會ReduxRedux
- 不懂聖盃佈局?5種方式包教包會
- Redux 包教包會(一):介紹 Redux 三大核心概念Redux
- Redux 包教包會(三):各司其職,重拾初心Redux
- Redux 包教包會(二):引入 combineReducers 拆分和組合狀態邏輯Redux
- AI在用 | 搞錢!免費AI開整治癒短影片,包教包會!AI
- imtoken錢包是什麼?imtoken錢包教程
- 切圖仔最後的倔強:包教不包會設計模式 - 結構型設計模式
- 比特幣入門 ② - 錢包比特幣
- 包教包會!7段程式碼帶你玩轉Python條件語句(附程式碼)Python
- 短小精悍的npm入門級保姆教程,一篇包會NPM
- Golang閉包入門瞭解Golang
- nginx-安裝Nginx
- Nginx-基礎Nginx
- 2萬字長文包教包會 JVM 記憶體結構 保姆級學習筆記JVM記憶體筆記
- IDEA 匯出和匯入jar包教程IdeaJAR
- npm入門(二)—package(包)的管理NPMPackage
- Nginx-基礎篇Nginx
- 【 nginx-負載均衡 】圖文並茂,一看就會Nginx負載
- Go 入門 – 包,函式和變數Go函式變數
- Nginx-執行管理篇Nginx
- Nginx-正向代理實現Nginx
- 最簡明的 Tcpdump 抓包入門指南TCP
- 工良出品:包教會,Hadoop、Hive 搭建部署簡易教程HadoopHive
- python mesa包教程Python
- 前端入門19-JavaScript進階之閉包前端JavaScript
- 包郵送書啦 |《機器學習入門》機器學習
- Python基礎入門(8)- Python模組和包Python
- 小入門 Django(做個疫情資料包告)Django
- Netty入門系列(2) --使用Netty解決粘包和拆包問題Netty
- 想知道jsonp到底是怎麼實現的?看我,包教會!JSON
- RE|Nginx-安裝與配置(1)Nginx
- Aapche POI java excel 操作工具包入門JavaExcel
- Go語言的context包從放棄到入門GoContext
- 🔥《吐血整理》進階系列教程 - 拿捏 Fiddler 抓包教程 (11)-Fiddler 設定安卓手機抓包,不會可是萬萬不行的!安卓
- 入門入門入門 MySQL命名行MySql
- nginx-通過lua動態更改upstreamNginx
- 一看就會的 egret 入門教程