Nginx-包教包會-入門

lvxfcjf發表於2021-09-09

前言

Nginx 作為 web 伺服器 以低記憶體,高擴充套件,並且輕鬆單機支援 1-3w (據說可以單機 10w,但沒有看到具體的機器配置)的併發連結的特性廣受開發人員的青睞。

推薦在 linux 系統上使用 Nginx ,這會充分利用 linux 的特性,效能比在 windows 上會更好。

本文主要內容:

  • Nginx 簡單配置
  • root 和 alias 的區別
  • location 的優先順序及驗證
  • Nginx 內建變數介紹
  • if
  • rewrite 轉發
  • try_files
  • 配置 gzip
  • 協商快取和強快取的介紹和配置

後續章節,我會使用 ab 壓測來一步一步最佳化 Nginx 的配置,Nginx 知道原理,懂得常用配置即可。有的效能最佳化需要了解 linux 核心httptcp 相關的東西,如果你不想了解,可以記錄一份自己的配置即可,不必糾結為什麼。

本文內容在 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 / {} 匹配所有的資源。

listenserver_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 獲取 pathquery string

訪問

$request_uri/arg/a/?q1=q1canshu&bb=2323

$scheme 獲取請求協議

值為 httphttps

$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 的內容。

驗證 redirectpermanent

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-MatchLast-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 ,值為 Etagnginx 校驗是否一樣,一樣說明快取沒有過期,返回狀態碼 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-Modifiednginx 收到 If-Modified-Since 後,根據配置 if_modified_since 屬性比較資源的最後修改時間(Last-Modified)和該值If-Modified-Since進行比較,匹配成功,則命中快取,返回304,否則返回 資源,狀態碼為 200,並更新快取時間。

強制快取

Expires

Expireshttp1.0 的規範,它的值是一個絕對時間的GMT格式的時間字串。這個時間代表的該資源的失效時間,如果在該時間之前請求的話,則都是從快取裡面讀取的。如果服務端和客戶端時區不一致會導致判斷不準確。

Cache-Control

Cache-Controlhttp1.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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章