天天看點

nginx 之 proxy_pass 接口轉發的規則

今天上了一個多頁應用,發現接口轉發後是 401。 最後發現是接口轉發出錯了。位址裡多拼了一個 路徑。 以前我一直以為location 字段會替換掉 proxy_pass 裡面配置的 url 位址。 今天了解了一下 發現還是有不少細節的。

// node js 檔案,列印請求路徑。友善檢視後端真實接受到的請求位址

const http = require('http');

http.createServer((req, res) => {

  console.log(req.url);

  res.end(`您的 請求 位址是${req.url}`);

}).listen(3000);

proxy_pass 如何轉發,首先看 proxy_pass 的url 配置。

proxy_pass 隻是HOST

proxy_pass 隻是HOST,不包含任何路徑,比如

* http://host - √

* https://host - √

* http://host:port - √

* https://host:port - √

* http://host/ - x

* http://host:port/ - x

這種情況下,會把比對到的所有路徑直接穿透轉發。比如以下的配置

 location /api/ {

    proxy_pass http://127.0.0.1:3000;

 }

通路 http://127.0.0.1:80/api/cc, 後端結果為 您的 請求 位址是/api/cc

proxy_pass 包含路徑

這裡的路徑哪怕隻是一個 / 也是存在的,如:

http://host - x

https//host/ - √

http://host:port- x

https://host:port/ - √

http://host/api - √

http://host/api/ - √

這種情況下,url 裡面會去掉 location 比對的字元串,拼接到 proxy_pass 再進行轉發。

 location /api/ {

    proxy_pass http://127.0.0.1:3000/;

 }

通路 http://127.0.0.1:81/api/cc, 後端結果為 您的 請求 位址是/cc

重寫代理連結 - url rewrite

使用 rewrite 指令并且生效後,proxy_pass url 連結中的路徑會被忽略,如:

server {

            listen       83;

            location / {

                rewrite ^/api/(.*) /fixpath=$1 break;

                proxy_pass http://127.0.0.1:3000/node/;

            }

            location ^/api/ {

                rewrite ^/api/(.*) /fixpath=$1 break;

                proxy_pass http://127.0.0.1:3000/node/;

            }

        }

通路 http://127.0.0.1:83/bb/cc 得到 您的 請求 位址是/node/bb/cc(比對上 / 了,沒有比對 rewrite)

通路 http://127.0.0.1:83/api/cc 得到 您的 請求 位址是/fixpath=cc (我們寫的 proxy_pass http://127.0.0.1:3000/node/ 裡面的 node路徑丢失了 )

知道了這幾點,碰到轉發接口也有一點底氣啦~

更多

在github上看到的這本小書 ⬇️

(參考資料)[https://xuexb.github.io/learn...]

我的 nginx 配置

events {

}

http {

    # proxy_pass url 隻是 host

    # 這時候 location 比對的完整路徑将直接透傳給 url ,如:

     server {

            listen       80;

            location / {

                proxy_pass http://127.0.0.1:3000;

            }

            location /api/ {

                proxy_pass http://127.0.0.1:3000;

            }

        }

    # url 包含路徑

    # 當 proxy_pass url 的 url 包含路徑時,比對時會根據 location 的比對後的連結透傳給 url ,注意比對後就是這樣:

     server {

            listen       81;

            location / {

                proxy_pass http://127.0.0.1:3000/;

            }

            location /api/ {

                proxy_pass http://127.0.0.1:3000/;

            }

            location /bpi/ {

                proxy_pass http://127.0.0.1:3000/v1;

            }

            location /cpi {

                proxy_pass http://127.0.0.1:3000/v1;

            }

        }

        # 當 location 以正則形式比對時,proxy_pass 就不能以 / 結束了,也就是不能包含路徑了, 會提示配置錯誤,比如錯誤的:

     server {

            listen       82;

            location / {

                proxy_pass http://127.0.0.1:3000/;

            }

        # nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /test.conf:47

        #    location ~* ^/api/ {

        #         proxy_pass http://127.0.0.1:3000/;

        #     }

        # nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /Users/tangdaoyuan/code/anheng/jz-bingjiang/test.conf:52

        #    location ~* ^/api/ {

        #         proxy_pass http://127.0.0.1:3000/b1;

        #     }

        }

    # 使用 rewrite 指令并且生效後,proxy_pass url 連結中的路徑會被忽略,如:

     server {

            listen       83;

            location / {

                proxy_pass http://127.0.0.1:3000/node/;

            }

            location ^/api/ {

                rewrite ^/api/(.*) /fixpath=$1 break;

                proxy_pass http://127.0.0.1:3000/node/;

            }

        }

}

測試流程 : node 運作 服務, 啟動Nginx 轉發 , 再用postman 發送請求。

繼續閱讀