[英]Redirecting captured regex group using nginx
使用以下 nginx 位置指令
location ~* (.*)(\/graphql)$ {
proxy_pass http://my-backend:80/$2;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
我希望像https://example.com/anything/graphql
這樣的 URL 被重定向到http://my-backend:80/$2
但事實並非如此,因為每當我嘗試訪問 URL 時,nginx 都會給我一個 404 錯誤以/graphql
。 錯誤將是
[error] 31#31: *1 no resolver defined to resolve my-backend, client: 172.18.0.1, server: localhost, request: "GET /anything/graphql HTTP/2.0", host: "localhost"
這是一個已知的 nginx 限制,您不能在正則表達式位置內為proxy_pass
指定 URI。 如果你嘗試做類似的事情
proxy_pass http://my-backend/graphql;
你有以下 nginx 錯誤:
nginx:[emerg]“proxy_pass”在正則表達式給出的位置、命名位置內、“if”語句內或“limit_except”塊內不能有 URI 部分......
你有兩個選擇。 第一個是使用變量將您想要的任何內容作為 URI 傳遞給上游,可以是您選擇的方式,或者如果它是常量字符串,則明確指定您的端點,例如
set $endpoint graphql;
proxy_pass http://my_backend/$endpoint;
但是,這種方法有一個您已經面臨的缺點 - 如果您的上游是通過主機名而不是 IP 地址指定的,則需要定義resolver
。 那就是
proxy_pass http://localhost/$endpoint;
配置行需要一個解析器,而
proxy_pass http://127.0.0.1/$endpoint;
不需要它。 $endpoint
變量僅用於 URI 部分並不重要。 如果您想知道該resolver
的需求是什么,讓我引用已經提到的博客文章中最相關的部分:
Linux,POSIX 等僅提供一種從名稱獲取 IP 的方法:
gethostbyname
。 如果你花時間閱讀手冊頁(總是一件安全的事情......;))你會意識到解析名稱有很多工作要做:打開文件,詢問 NIS 或 YP 他們是怎么想的,詢問 DNS 服務器(可能有幾種不同的方式)。 而這一切都是同步的。 現在您已經習慣了 nginx 方式,您知道這有多糟糕並且您不希望 go 走下丑陋的同步方式。 因此,忠於自己的 Igor 重新實現了 DNS 查找(請注意,使用內存緩存)只是為了避免調用這個丑陋的阻塞gethostbyname
... 這就是我們有這個額外的resolver
指令的原因。 是的,編碼最快的 web 服務器是有代價的……
當除了使用變量和proxy_pass
別無他法時,使用像8.8.8.8
這樣的公共 DNS 是一種選擇,但是設置你自己的本地應該更高效(或者你將與8.8.8.8
進行持續的流量交換8.8.8.8
主機)。 但是還有另一種選擇。 您可以將 location 塊內的 URI 重寫為所需的 URI,並使用proxy_pass
而不使用任何其他變量:
location ~ /graphql$ {
rewrite ^ /graphql break;
proxy_pass http://my-backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
對於大多數情況,這是一種更方便的方法,因為使用這樣的配置您根本不需要任何指定的resolver
。
如您所見,我在這里沒有使用任何捕獲組,因為使用它們來解決您的特定情況沒有任何實際意義。 給定的正則表達式與您的正則表達式完全相同(同時性能稍高)。 然而,有些情況下你真的需要使用它們,如果真正需要使用捕獲組的人會讀到這篇文章,他必須被警告做類似的事情的直接方法
location ~ (/graphql)$ {
rewrite ^ $1 break;
...
不會工作。 原因是每當正則表達式模式匹配操作取代時,編號的捕獲都會被重新評估,而rewrite
指令正是執行此類操作的指令之一(使$1
成為空字符串)。 解決方案是改用命名捕獲組:
location ~ (?<url>/graphql)$ {
rewrite ^ $url break;
...
或者可以重用正則表達式模式(我認為性能會稍差):
location ~ /graphql$ {
rewrite (/graphql)$ $1 break;
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.