要讓第一層Nginx將客戶端請求的URL完整透傳到第二層Nginx,關鍵在于正確配置proxy_pass
指令及路徑拼接規則。以下是具體配置方法和注意事項:
核心配置原則
proxy_pass
指令末尾是否添加/
會直接影響URL的透傳方式:
- 不帶
/
:會將location
匹配的路徑連同后續URI一起轉發 - 帶
/
:僅轉發location
匹配路徑之后的URI(相當于截斷匹配路徑)
場景1:完整透傳所有URL(推薦)
如果希望第一層Nginx將客戶端請求的完整URL(包括路徑和參數)原封不動地轉發到第二層Nginx,配置如下:
第一層Nginx配置
server {listen 80;server_name example.com;# 匹配所有請求(或指定路徑,如/location/)location / {# 關鍵:proxy_pass末尾不帶/,確保完整透傳URLproxy_pass http://第二層Nginx的IP:端口; # 例如 http://192.168.1.101:8080# 傳遞原始請求頭(確保第二層能獲取完整URL信息)proxy_set_header Host $host; # 傳遞客戶端訪問的域名proxy_set_header X-Original-URI $request_uri; # 傳遞完整URI(含參數)proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}
}
第二層Nginx配置
server {listen 8080; # 接收第一層轉發的端口# 直接處理轉發過來的完整URLlocation / {# 轉發到實際業務服務(如后端API)proxy_pass http://業務服務IP:端口; # 例如 http://192.168.1.200:8080# 同樣傳遞頭信息(如需業務服務獲取原始URL)proxy_set_header Host $host;proxy_set_header X-Original-URI $http_x_original_uri; # 傳遞第一層的原始URI}
}
場景2:URL路徑改寫后透傳
如果需要在第一層Nginx修改URL路徑后再轉發(例如添加前綴),可使用rewrite
指令:
第一層Nginx配置(路徑改寫示例)
server {listen 80;server_name example.com;# 客戶端訪問 /api/xxx 時,轉發到第二層的 /prefix/api/xxxlocation /api/ {# 改寫URL路徑(在原路徑前添加/prefix)rewrite ^/api/(.*)$ /prefix/api/$1 break;# 轉發到第二層(末尾帶/,配合rewrite使用)proxy_pass http://192.168.1.101:8080;# 傳遞頭信息proxy_set_header Host $host;proxy_set_header X-Original-URI $request_uri; # 保留原始請求的URI}
}
關鍵驗證方法
-
測試URL透傳是否正確:
使用curl
發送請求并查看第二層Nginx的日志:# 客戶端請求 curl http://example.com/path?param=123# 查看第二層Nginx的access.log,確認日志中的請求路徑是否為/path?param=123
-
檢查原始URI:
第二層Nginx可通過$http_x_original_uri
變量獲取客戶端原始請求的完整URL(需第一層配置X-Original-URI
頭)。
常見問題解決
- 路徑被截斷:若發現URL路徑丟失,檢查
proxy_pass
末尾是否多了/
,去掉即可完整透傳。 - 參數丟失:Nginx默認會透傳URL參數,無需額外配置,若參數丟失可能是后端服務處理問題。
- 域名不匹配:確保
proxy_set_header Host $host
配置正確,否則第二層可能因Host不匹配拒絕請求。
通過以上配置,即可實現第一層Nginx到第二層Nginx的URL完整透傳,適用于需要多級代理且保留原始請求路徑的場景。
rewrite指令
rewrite ^/api/(.*)$ /prefix/api/$1 break;
是 Nginx 中用于 URL 路徑改寫的核心指令,其作用是將客戶端請求的 URL 路徑按照指定規則重新改寫,再轉發到后端服務。下面詳細解釋其用法和工作原理:
rewrite指令拆解
-
rewrite
:Nginx 的 URL 重寫指令,用于修改請求的 URI 路徑。 -
^/api/(.*)$
:正則表達式匹配規則(匹配客戶端原始請求路徑):^
:表示字符串的開始/api/
:固定匹配以/api/
開頭的路徑(如/api/user
、/api/order/123
)(.*)
:捕獲組,匹配/api/
后面的所有字符(包括子路徑和參數),.*
表示任意字符任意長度$
:表示字符串的結束
-
/prefix/api/$1
:改寫后的目標路徑:/prefix/api/
:在原始路徑前添加的固定前綴$1
:引用前面正則表達式中(.*)
捕獲的內容(即/api/
后面的部分)
-
break
:改寫規則的終止標記,意思是“一旦匹配并完成改寫,就停止后續的rewrite
規則處理”。
實際效果示例
當客戶端請求以下路徑時,會被改寫成對應的新路徑:
客戶端原始請求路徑 | 改寫后的路徑(轉發給后端) | 說明 |
---|---|---|
/api/user | /prefix/api/user | $1 捕獲 user |
/api/order/123?type=1 | /prefix/api/order/123?type=1 | $1 捕獲 order/123?type=1 (含參數) |
/api/v2/product | /prefix/api/v2/product | $1 捕獲 v2/product |
關鍵注意事項
-
與
proxy_pass
配合使用:
該rewrite
指令通常用于location
塊中,配合proxy_pass
轉發到后端服務。例如:location /api/ {# 先改寫路徑rewrite ^/api/(.*)$ /prefix/api/$1 break;# 再轉發到后端(注意 proxy_pass 末尾是否帶 / 不影響這里的改寫結果,因為 rewrite 已處理)proxy_pass http://backend_server; }
-
break
標記的作用:- 如果用
break
:改寫后立即停止后續rewrite
規則,直接用新路徑轉發。 - 如果用
last
:改寫后會重新發起一次請求匹配(可能匹配到其他location
),適合更復雜的多級改寫。 - 此處用
break
是最常見的場景,避免重復改寫。
- 如果用
-
不影響客戶端可見的 URL:
這種改寫是“內部改寫”,客戶端瀏覽器地址欄的 URL 不會變化,僅 Nginx 內部轉發時使用新路徑。 -
參數保留:
原始 URL 中的查詢參數(如?type=1
)會被自動保留到改寫后的路徑中,無需額外配置。
適用場景
- 當后端服務要求路徑必須包含特定前綴(如
/prefix/
),但客戶端請求的路徑沒有該前綴時,用于統一添加前綴。 - 實現不同客戶端請求路徑到后端服務路徑的映射(如兼容舊版 API 路徑)。
- 配合多級代理時,在第一層 Nginx 統一調整路徑后再轉發給第二層 Nginx。
通過這個規則,可以靈活地在 Nginx 層面調整請求路徑,而無需修改客戶端或后端服務的代碼。