徹底搞懂 Nginx 的五大應用場景
一、HTTP 服務器
Nginx 本身也是一個靜態資源的服務器,當只有靜態資源的時候,就可以使用 Nginx 來做服務器,如果一個網站只是靜態頁面的話,那麼就可以通過這種方式來實現部署。
1、 首先在文檔根目錄Docroot(/usr/local/var/www)
下創建 html 目錄, 然後在 html 中放一個 test.html;
2、 配置nginx.conf
中的 server
user mengday staff;
http {
server {
listen 80;
server_name localhost;
client_max_body_size 1024M;
# 默認location
location / {
root /usr/local/var/www/html;
index index.html index.htm;
}
}
}
3、訪問測試
-
http://localhost/
指向/usr/local/var/www/index.html
, index.html 是安裝 nginx 自帶的 html -
http://localhost/test.html
指向/usr/local/var/www/html/test.html
注意:如果訪問圖片出現 403 Forbidden 錯誤,可能是因爲 nginx.conf 的第一行 user 配置不對,默認是 #user nobody; 是註釋的,linux 下改成 user root; macos 下改成 user 用戶名 所在組; 然後重新加載配置文件或者重啓,再試一下就可以了, 用戶名可以通過 who am i 命令來查看。
4、指令簡介
-
server : 用於定義服務,http 中可以有多個 server 塊
-
listen : 指定服務器偵聽請求的 IP 地址和端口,如果省略地址,服務器將偵聽所有地址,如果省略端口,則使用標準端口
-
server_name : 服務名稱,用於配置域名
-
location : 用於配置映射路徑 uri 對應的配置,一個 server 中可以有多個 location, location 後面跟一個 uri, 可以是一個正則表達式, / 表示匹配任意路徑, 當客戶端訪問的路徑滿足這個 uri 時就會執行 location 塊裏面的代碼
-
root : 根路徑,當訪問
http://localhost/test.html
,“/test.html” 會匹配到”/”uri, 找到 root 爲/usr/local/var/www/html
,用戶訪問的資源物理地址 =root + uri = /usr/local/var/www/html + /test.html=/usr/local/var/www/html/test.html
-
index : 設置首頁,當只訪問
server_name
時後面不跟任何路徑是不走 root 直接走 index 指令的;如果訪問路徑中沒有指定具體的文件,則返回 index 設置的資源,如果訪問http://localhost/html/
則默認返回 index.html
5、location uri 正則表達式
-
.
:匹配除換行符以外的任意字符 -
?
:重複 0 次或 1 次 -
+
:重複 1 次或更多次 -
*
:重複 0 次或更多次 -
\d
:匹配數字 -
^
:匹配字符串的開始 -
$
:匹配字符串的結束 -
{n}
:重複 n 次 -
{n,}
:重複 n 次或更多次 -
[c]
:匹配單個字符 c -
[a-z]
:匹配 a-z 小寫字母的任意一個 -
(a|b|c)
: 屬線表示匹配任意一種情況,每種情況使用豎線分隔,一般使用小括號括括住,匹配符合 a 字符 或是 b 字符 或是 c 字符的字符串 -
\
反斜槓:用於轉義特殊字符
小括號 () 之間匹配的內容,可以在後面通過$1
來引用,$2
表示的是前面第二個 () 裏的內容。正則裏面容易讓人困惑的是\
轉義特殊字符。
二、靜態服務器
在公司中經常會遇到靜態服務器,通常會提供一個上傳的功能,其他應用如果需要靜態資源就從該靜態服務器中獲取。
1、在/usr/local/var/www
下分別創建 images 和 img 目錄,分別在每個目錄下放一張test.jpg
http {
server {
listen 80;
server_name localhost;
set $doc_root /usr/local/var/www;
# 默認location
location / {
root /usr/local/var/www/html;
index index.html index.htm;
}
location ^~ /images/ {
root $doc_root;
}
location ~* \.(gif|jpg|jpeg|png|bmp|ico|swf|css|js)$ {
root $doc_root/img;
}
}
}
自定義變量使用 set 指令,語法 set 變量名值; 引用使用變量名值; 引用使用變量名; 這裏自定義了 doc_root 變量。
靜態服務器 location 的映射一般有兩種方式:
-
使用路徑,如 /images/ 一般圖片都會放在某個圖片目錄下,
-
使用後綴,如 .jpg、.png 等後綴匹配模式
訪問http://localhost/test.jpg
會映射到 $doc_root/img
訪問http://localhost/images/test.jpg
當同一個路徑滿足多個 location 時,優先匹配優先級高的 location,由於^~
的優先級大於 ~
, 所以會走/images/
對應的 location
常見的 location 路徑映射路徑有以下幾種:
-
=
進行普通字符精確匹配。也就是完全匹配。 -
^~
前綴匹配。如果匹配成功,則不再匹配其他 location。 -
~
表示執行一個正則匹配,區分大小寫 -
~*
表示執行一個正則匹配,不區分大小寫 -
/xxx/
常規字符串路徑匹配 -
/
通用匹配,任何請求都會匹配到
location 優先級
當一個路徑匹配多個 location 時究竟哪個 location 能匹配到時有優先級順序的,而優先級的順序於 location 值的表達式類型有關,和在配置文件中的先後順序無關。相同類型的表達式,字符串長的會優先匹配。推薦:Java 面試題大全
以下是按優先級排列說明:
-
等號類型(=)的優先級最高。一旦匹配成功,則不再查找其他匹配項,停止搜索。
-
^~
類型表達式,不屬於正則表達式。一旦匹配成功,則不再查找其他匹配項,停止搜索。 -
正則表達式類型(
~ ~*
)的優先級次之。如果有多個 location 的正則能匹配的話,則使用正則表達式最長的那個。 -
常規字符串匹配類型。按前綴匹配。
-
/ 通用匹配,如果沒有匹配到,就匹配通用的
優先級搜索問題:不同類型的 location 映射決定是否繼續向下搜索
-
等號類型、
^~
類型:一旦匹配上就停止搜索了,不會再匹配其他 location 了 -
正則表達式類型 (
~ ~*
), 常規字符串匹配類型/xxx/
: 匹配到之後,還會繼續搜索其他其它 location,直到找到優先級最高的,或者找到第一種情況而停止搜索
location 優先級從高到底:
(location =
) > (location 完整路徑
) > (location ^~ 路徑
) > (location ~,~* 正則順序
) > (location 部分起始路徑
) > (/
)
location = / {
# 精確匹配/,主機名後面不能帶任何字符串 /
[ configuration A ]
}
location / {
# 匹配所有以 / 開頭的請求。
# 但是如果有更長的同類型的表達式,則選擇更長的表達式。
# 如果有正則表達式可以匹配,則優先匹配正則表達式。
[ configuration B ]
}
location /documents/ {
# 匹配所有以 /documents/ 開頭的請求,匹配符合以後,還要繼續往下搜索。
# 但是如果有更長的同類型的表達式,則選擇更長的表達式。
# 如果有正則表達式可以匹配,則優先匹配正則表達式。
[ configuration C ]
}
location ^~ /images/ {
# 匹配所有以 /images/ 開頭的表達式,如果匹配成功,則停止匹配查找,停止搜索。
# 所以,即便有符合的正則表達式location,也不會被使用
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
# 匹配所有以 gif jpg jpeg結尾的請求。
# 但是 以 /images/開頭的請求,將使用 Configuration D,D具有更高的優先級
[ configuration E ]
}
location /images/ {
# 字符匹配到 /images/,還會繼續往下搜索
[ configuration F ]
}
location = /test.htm {
root /usr/local/var/www/htm;
index index.htm;
}
注意:location 的優先級與 location 配置的位置無關
三、反向代理
反向代理應該是 Nginx 使用最多的功能了,反向代理 (Reverse Proxy) 方式是指以代理服務器來接受 internet 上的連接請求,然後將請求轉發給內部網絡上的服務器,並將從服務器上得到的結果返回給 internet 上請求連接的客戶端,此時代理服務器對外就表現爲一個反向代理服務器。
簡單來說就是真實的服務器不能直接被外部網絡訪問,所以需要一臺代理服務器,而代理服務器能被外部網絡訪問的同時又跟真實服務器在同一個網絡環境,當然也可能是同一臺服務器,端口不同而已。
反向代理通過proxy_pass
指令來實現。
啓動一個 Java Web 項目,端口號爲 8081
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://localhost:8081;
proxy_set_header Host $host:$server_port;
# 設置用戶ip地址
proxy_set_header X-Forwarded-For $remote_addr;
# 當請求服務器出錯去尋找其他服務器
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}
}
當我們訪問 localhost 的時候,就相當於訪問 localhost:8081
了
四、負載均衡
負載均衡也是 Nginx 常用的一個功能,負載均衡其意思就是分攤到多個操作單元上進行執行,例如 Web 服務器、FTP 服務器、企業關鍵應用服務器和其它關鍵任務服務器等,從而共同完成工作任務。
簡單而言就是當有 2 臺或以上服務器時,根據規則隨機的將請求分發到指定的服務器上處理,負載均衡配置一般都需要同時配置反向代理,通過反向代理跳轉到負載均衡。而 Nginx 目前支持自帶 3 種負載均衡策略,還有 2 種常用的第三方策略。
負載均衡通過 upstream 指令來實現。推薦:Java 面試題大全
1. RR(round robin : 輪詢 默認)
每個請求按時間順序逐一分配到不同的後端服務器,也就是說第一次請求分配到第一臺服務器上,第二次請求分配到第二臺服務器上,如果只有兩臺服務器,第三次請求繼續分配到第一臺上,這樣循環輪詢下去,也就是服務器接收請求的比例是 1:1, 如果後端服務器 down 掉,能自動剔除。輪詢是默認配置,不需要太多的配置
同一個項目分別使用 8081 和 8082 端口啓動項目
upstream web_servers {
server localhost:8081;
server localhost:8082;
}
server {
listen 80;
server_name localhost;
#access_log logs/host.access.log main;
location / {
proxy_pass http://web_servers;
# 必須指定Header Host
proxy_set_header Host $host:$server_port;
}
}
訪問地址仍然可以獲得響應 http://localhost/api/user/login?username=zhangsan&password=111111
,這種方式是輪詢的
2. 權重
指定輪詢幾率,weight 和訪問比率成正比, 也就是服務器接收請求的比例就是各自配置的 weight 的比例,用於後端服務器性能不均的情況, 比如服務器性能差點就少接收點請求,服務器性能好點就多處理點請求。
upstream test {
server localhost:8081 weight=1;
server localhost:8082 weight=3;
server localhost:8083 weight=4 backup;
}
示例是 4 次請求只有一次被分配到 8081 上,其他 3 次分配到 8082 上。backup 是指熱備,只有當 8081 和 8082 都宕機的情況下才走 8083
3. ip_hash
上面的 2 種方式都有一個問題,那就是下一個請求來的時候請求可能分發到另外一個服務器,當我們的程序不是無狀態的時候 (採用了 session 保存數據),這時候就有一個很大的很問題了,比如把登錄信息保存到了 session 中,那麼跳轉到另外一臺服務器的時候就需要重新登錄了,所以很多時候我們需要一個客戶只訪問一個服務器,那麼就需要用 iphash 了,iphash 的每個請求按訪問 ip 的 hash 結果分配,這樣每個訪客固定訪問一個後端服務器,可以解決 session 的問題。
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}
4. fair(第三方)
按後端服務器的響應時間來分配請求,響應時間短的優先分配。這個配置是爲了更快的給用戶響應
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}
5. url_hash(第三方)
按訪問 url 的 hash 結果來分配請求,使每個 url 定向到同一個後端服務器,後端服務器爲緩存時比較有效。在 upstream 中加入 hash 語句,server 語句中不能寫入 weight 等其他的參數,hash_method
是使用的 hash 算法
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}
以上 5 種負載均衡各自適用不同情況下使用,所以可以根據實際情況選擇使用哪種策略模式, 不過 fair 和 url_hash 需要安裝第三方模塊才能使用。
五、動靜分離
動靜分離是讓動態網站裏的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以後,我們就可以根據靜態資源的特點將其做緩存操作,這就是網站靜態化處理的核心思路。
upstream web_servers {
server localhost:8081;
server localhost:8082;
}
server {
listen 80;
server_name localhost;
set $doc_root /usr/local/var/www;
location ~* \.(gif|jpg|jpeg|png|bmp|ico|swf|css|js)$ {
root $doc_root/img;
}
location / {
proxy_pass http://web_servers;
# 必須指定Header Host
proxy_set_header Host $host:$server_port;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root $doc_root;
}
}
六、其他
1.return 指令
返回 http 狀態碼 和 可選的第二個參數可以是重定向的 URL
location /permanently/moved/url {
return 301 http://www.example.com/moved/here;
}
2. rewrite 指令
重寫 URI 請求 rewrite,通過使用 rewrite 指令在請求處理期間多次修改請求 URI,該指令具有一個可選參數和兩個必需參數。
第一個 (必需) 參數是請求 URI 必須匹配的正則表達式。
第二個參數是用於替換匹配 URI 的 URI。
可選的第三個參數是可以停止進一步重寫指令的處理或發送重定向 (代碼 301 或 302) 的標誌
location /users/ {
rewrite ^/users/(.*)$ /show?user=$1 break;
}
3. error_page 指令
使用 error_page 指令,您可以配置 NGINX 返回自定義頁面以及錯誤代碼,替換響應中的其他錯誤代碼,或將瀏覽器重定向到其他 URI。在以下示例中,error_page
指令指定要返回 404 頁面錯誤代碼的頁面 (/404.html)。
error_page 404 /404.html;
4. 日誌
訪問日誌:需要開啓壓縮 gzip on; 否則不生成日誌文件,打開log_format
、access_log
註釋
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /usr/local/etc/nginx/logs/host.access.log main;
gzip on;
5. deny 指令
# 禁止訪問某個目錄
location ~* \.(txt|doc)${
root $doc_root;
deny all;
}
6. 內置變量
nginx 的配置文件中可以使用的內置變量以美元符$
開始,也有人叫全局變量。其中,部分預定義的變量的值是可以改變的。另外,關注 Java 知音公衆號,回覆 “後端面試”,送你一份面試題寶典!
-
$args
:#
這個變量等於請求行中的參數,同$query_string
-
$content_length
:請求頭中的 Content-length 字段。 -
$content_type
:請求頭中的 Content-Type 字段。 -
$document_root
:當前請求在 root 指令中指定的值。 -
$host
:請求主機頭字段,否則爲服務器名稱。 -
$http_user_agent
:客戶端 agent 信息 -
$http_cookie
:客戶端 cookie 信息 -
$limit_rate
:這個變量可以限制連接速率。 -
$request_method
:客戶端請求的動作,通常爲 GET 或 POST。 -
$remote_addr
:客戶端的 IP 地址。 -
$remote_port
:客戶端的端口。 -
$remote_user
:已經經過 Auth Basic Module 驗證的用戶名。 -
$request_filename
:當前請求的文件路徑,由 root 或 alias 指令與 URI 請求生成。 -
$scheme
:HTTP 方法(如 http,https)。 -
$server_protocol
:請求使用的協議,通常是 HTTP/1.0 或 HTTP/1.1。 -
$server_addr
:服務器地址,在完成一次系統調用後可以確定這個值。 -
$server_name
:服務器名稱。 -
$server_port
:請求到達服務器的端口號。 -
$request_uri
:包含請求參數的原始 URI,不包含主機名,如:”/foo/bar.php?arg=baz
”。 -
$uri
:不帶請求參數的當前 URI,$uri
不包含主機名,如”/foo/bar.html
”。 -
$document_uri
:與$uri
相同
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/HSClbgx_m_IVhfOUCF0RBg