簡體   English   中英

使用 nginx 重定向捕獲的正則表達式組

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM