之前說了很多關于 Nginx 模塊的內容,還有一部分非常重要的內容,那就是 Nginx 的變數,變數在 Nginx 中可以說無處不在,認識了解這些變數的作用和原理同樣是必要的,下面幾乎囊括了關于 Nginx 的所有變數,單獨看起來可能比較枯燥,放心,后面依然有實戰內容,
Nginx 變數的運行原理
圍繞 Nginx 中的變數模塊可以分為兩類,一類是提供變數的模塊,另外一類是使用變數的模塊,
- 提供變數的模塊
- 在 Preconfiguration 源代碼中定義變數名以及可以決議出變數的方法
- 使用變數的模塊
- 決議 nginx.conf 時定義變數的使用方式
也就是在 Nginx 啟動時,已經定義了變數,而只有當真正處理請求的時候,才會根據 nginx.conf 決議出來的變數使用方式呼叫 Preconfiguration 中定義的方法來實際獲取值,
這也是變數的兩個特性:
- 惰性求值:只有使用的時候才會去調方法決議
- 變數值可以時刻變化,其值為使用的那一時刻的值,例如發送回應包體位元組數,實際在發送的程序中是一直在變化的,
除了 Nginx 的模塊之外,Nginx 框架也包含許多的變數,這些變數不需要通過編譯模塊來引入,而且,Nginx 框架所提供的變數往往反映了處理請求的細節,因此,了解 Nginx 框架所提供的變數是十分有必要的,
HTTP 請求相關的變數
先來看一下關于 HTTP 請求的相關變數,
-
arg_引數名:URL 中某個具體引數的值
-
query_string:與 args 變數完全相同
-
args:全部 URL 引數
-
is_args:如果請求 URL 中有引數則回傳 ?,否則回傳空
-
content_length:HTTP 請求中標識包體長度的 Content-Length 頭部的值,如果請求中沒有攜帶這個引數,那么就取不到對應的值,
-
content_type:標識請求包體型別的 Content-Type 頭部的值,同樣需要用戶請求中攜帶對應的引數,
-
uri:請求的 URI(不同于 URL,不包括 ? 后的引數)
-
document_uri:與 uri 完全相同,由于歷史原因而存在的,
-
request_uri:請求的 URL(包括 URI 以及完整的引數)
-
scheme:協議名,例如 HTTP 或者 HTTPS
-
request_method:請求方法,例如 GET 或者 POST
-
request_length:所有請求內容的大小,包括請求行、頭部、包體等
-
remote_user:由 HTTP Basic Authentication 協議傳入的用戶名
-
request_body_file:很多時候會將用戶請求的包體存放到檔案中,這個變數就是臨時存放請求包體的檔案
- 如果包體非常小則不會存檔案
- client_body_in_file_only 指令強制所有包體存入檔案,且可決定是否洗掉
-
request_body:請求中的包體,這個變數當且僅當使用反向代理,且設定用記憶體暫存包體時才有效
-
request:原始的 URL 請求,含有方法與協議版本,例如 GET /?a=1&b=22 HTTP/1.1
-
host
- 先從請求行中獲取
- 如果含有 Host 頭部,則用其值替換掉請求行中的主機名
- 如果前兩者都取不到,則使用匹配上的 server_name
-
http_頭部名字:回傳一個具體請求頭部的值
特殊變數,這些變數會做一些處理,
- http_host
- http_user_agent
- http_referer
- http_via
- http_x_forwarded_for
- http_cookie
通用變數,除了以上的變數,都可以取到對應的值,
TCP 連接相關的變數
下面是關于 TCP 連接的變數,
- binary_remote_addr:客戶端地址的整形格式,對于 IPv4 是 4 位元組,對于 IPv6 是 16 位元組,所以在 limit_req 和 limit_conn 中通常可以用作 key (詳見:Nginx 處理 HTTP 請求的 11 個階段 中的 preaccess 階段)
- connection:遞增的連接序號
- connection_requests:當前連接上執行過的請求數,對 keepalive 連接有意義
- remote_addr:客戶端地址
- remote_port:客戶端埠
- proxy_protocol_addr:若使用了 proxy_protocol 協議,則回傳協議中的地址,否則回傳空
- proxy_protocol_port:若使用了 proxy_protocol 協議則回傳協議中的埠,否則回傳空
- server_addr:服務端地址
- server_port:服務器端埠
- TCP_INFO:TCP 內核層引數,包括 $tcpinfo_rtt, ?$tcpinfo_rttvar,?$tcpinfo_snd_cwnd, $tcpinfo_rcv_space
- server_protocol:服務器端協議,例如 HTTP/1.1
Nginx 處理請求程序中產生的變數
Nginx 處理 HTTP 請求的程序中也會產生很多變數,
- request_time:請求處理到現在的耗時,單位為秒,精確到毫秒
- server_name:匹配上請求的 server_name 值
- https:如果開啟了 TLS/SSL 則回傳 on,否則回傳空
- request_completion:若請求處理完則回傳 OK,否則回傳空
- request_id:以 16 進制輸出的請求表示 id,該 id 共含有 16 個位元組,是隨機生成的
- request_filename:待訪問檔案的完整路徑
- document_root:由 URI 和 root、alias 規則生成的檔案夾路徑
- realpath_root:將 document_root 中的軟鏈接等換成真實路徑
- limit_rate:回傳客戶端回應時的速度上限,單位為每秒位元組數,可以通過 set 指令修改對請求產生的效果
發送 HTTP 回應時相關的變數
-
body_bytes_sent:回應中 body 包體的長度
-
bytes_sent:全部 http 回應的長度
-
status:http 回應中的回傳碼
-
sent_trailer_名字:把回應結尾內容里的值回傳
-
sent_http_頭部名字:回應中某個具體頭部的值
特殊處理,下面這些變數需要經過特殊處理:
- sent_http_content_type
- sent_http_content_length
- sent_http_location
- sent_http_last_modified
- sent_http_connection
- sent_http_keep_alive
- sent_http_transfer_encoding
- sent_http_cache_control
- sent_http_link
通用:除了上面這些頭部,其他的頭部都是通用型的,也就是可以直接拿來用,
Nginx 系統變數
- time_local:以本地時間標準輸出的當前時間,例如 14/Nov/2018:15:55:37 +0800
- time_iso8601:使用 ISO8601 標準輸出的當前時間,例如 2018-11-14T15:55:37+08:00
- nginx_version:Nginx 版本號
- pid:所屬 worker 行程的行程 id
- pipe:使用了管道則回傳 p,否則回傳 .
- hostname:所在服務器的主機名,與 hostname 命令輸出一致
- msec:1970 年 1 月 1 日到現在的時間,單位為秒,小數點后精確到毫秒
實戰
組態檔:
log_format vartest '$remote_addr - $remote_user [$time_local] "$request" '
'$status bytes_sent=$bytes_sent body_bytes_sent=$body_bytes_sent "$http_referer" '
'"$http_user_agent" "$sent_http_abc"';
server {
server_name var.ziyang.com localhost;
#error_log logs/myerror.log debug;
access_log logs/vartest.log vartest;
listen 9090;
location / {
set $limit_rate 10k;
# return 200; tcpinfo: $tcpinfo_rtt,$tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space
return 200 '
arg_a: $arg_a,arg_b: $arg_b,args: $args
connection: $connection,connection_requests: $connection_requests
cookie_a: $cookie_a
uri: $uri,document_uri: $document_uri, request_uri: $request_uri
request: $request
request_id: $request_id
server: $server_addr,$server_name,$server_port,$server_protocol
host: $host,server_name: $server_name,http_host: $http_host
limit_rate: $limit_rate
hostname: $hostname
content_length: $content_length
status: $status
body_bytes_sent: $body_bytes_sent,bytes_sent: $bytes_sent
time: $request_time,$msec,$time_iso8601,$time_local
';
}
}
從上面這個組態檔中,我們可以看出來,回傳的回應里面包含了一系列的變數,實際驗證一下:
? test_nginx curl -H 'Content-Length: 0' -H 'Cookie: a=c1' 'localhost:9090?a=1&b=22'
arg_a: 1,arg_b: 22,args: a=1&b=22
connection: 2,connection_requests: 1
cookie_a: c1
uri: /,document_uri: /, request_uri: /?a=1&b=22
request: GET /?a=1&b=22 HTTP/1.1
request_id: 5d40b1ff29d2b87d5db5c4f95ebf5e4d
server: 127.0.0.1,var.ziyang.com,9090,HTTP/1.1
host: localhost,server_name: var.ziyang.com,http_host: localhost:9090
limit_rate: 10240
hostname: yuanzizhen.local
content_length: 0
status: 200
body_bytes_sent: 0,bytes_sent: 0
time: 0.000,1590842354.866,2020-05-30T20:39:14+08:00,30/May/2020:20:39:14 +0800
大家可以對比一下回應和組態檔中的值是不是一一對應的,更加深刻的理解一下變數的含義,
好了,這一節咱們學習了,關于 Nginx 的變數就講完了,下一節講一下實際應用變數的兩個模塊,大家會有更深刻的理解,
本文首發于我的個人博客:iziyang.github.io,所有組態檔我已經放在了 Nginx 組態檔,大家可以自取,
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/56810.html
標籤:Linux
