最近單位裏面調整應用端口和防火牆配置,原先起在 80 端口上的服務,須要調整到 8180 端口上進行部署。爲了對公網的影響度最小,公網端口依舊採用的 80 端口暴露服務,由網絡的同事在 WAF 側作了一個 80 到 8180 端口的映射。造成了一個這樣的網絡拓撲(脫敏簡化)圖。html
造成這樣的網絡拓撲以後,按理公網上訪問 http://test.snowheart.cn/ 時便可正常訪問到後臺的應用服務。But,後端有一些地方用到了 sendRedirect(url) 方法,這就致使了在進行 302 網絡跳轉的時候,Response 的 Location Header 上面帶了內部的端口,即造成了下述形式的 Location Header。java
HTTP/1.1 302 Moved Temporarily Date: Mon, 11 May 2020 15:45:29 GMT Location: http://test.snowheart.cn:8180/app/login.jsp Content-Type: text/html;charset=utf-8 Connection: close Transfer-Encoding: chunked
瀏覽器在進行跳轉時,使用了前面一個請求的 Location,在公網上請求了 8180 端口,由於防火牆的緣故,沒法訪問,報錯。nginx
在 HTTP 的 Code 響應碼中,301 表示永久重定向,302 表示臨時重定向。git
// DemoServlet1 // 經過設置 Header 和 Status,來進行重定向操做,其餘什麼都不作 response.setHeader("Location", request.getContextPath() + "/hello.html"); response.setStatus(302);
上述例子中的 Servlet URL,在瀏覽器中訪問以後,你會發現瀏覽器被重定向到了項目中的 /hello.html,其代碼在實現結果上,等價於下面的代碼:github
// DemoServlet2 // 經過 sendRedirect(url) 來進行重定向操做,其餘什麼都不作 response.sendRedirect(request.getContextPath() + "/hello.html");
若是 WAF 上是同端口透明出去了,公網和內網前置機的 Port 一致;shell
鏈路上除前置機應用端口爲 8180 外,其他地方端口均與此無關;後端
只是依賴 Apache 或 Nginx 的反向代理,是不會出現後端 Port 暴露的事情;瀏覽器
看來是在 WAF 作了端口轉換以後,內網前置機的 Apache 並不知道公網上的端口已是 80 了,故在 Location 上增長了 8180 端口的信息;服務器
亦可經過在各環節打印日誌的形式,來檢測 8180 端口是哪一個環節增長的...
故:咱們斷定,在從前置機 Apache 返回時,Location 上就已經有了前面的域名 + 端口,如今須要作的事情就是在返回以前,將 Location 上的端口給抹掉,亦或者是將 Location 上的域名 + 端口給抹掉,僅剩餘從 / 開始的 URI 地址。網絡
最早時候,想經過本身最熟悉的 Nginx 來進行 HTTP Response Header 的重寫
Windows 下的 Nginx 程序包沒法進行再次編譯,沒有辦法來加載其餘 Nginx 模塊;故須要使用 Linux 下的 Nginx 服務,以最大限度地與服務器保持一致。
# 下載最新的 ngx_headers_more 模塊包 wget https://github.com/openresty/headers-more-nginx-module/archive/v0.33.tar.gz tar -xzvf v0.33.tar.gz # 跳轉到 Nginx 目錄 # 查看 Nginx 編譯參數 ./nginx -V # 跳轉至 Nginx 源碼目錄,增長 ngx_headers_more 配置並編譯 # 每一個人的目錄都不相同,僅供參考 ./configure --prefix=/usr/local/nginx/server --with-http_stub_status_module --with-http_ssl_module --with-pcre=/tool/pcre-8.44 --with-http_realip_module --with-http_sub_module --with-http_gzip_static_module --add-module=/tool/echo-nginx-module-0.62rc1 --add-module=/tool/headers-more-nginx-module-0.33 make # 切記,不要 make install,不然會覆蓋掉以前Nginx的配置文件這些。 cp /usr/local/nginx/server/sbin/nginx /usr/local/nginx/server/sbin/nginx.origin cp objs/nginx /usr/local/nginx/server/sbin/nginx
map $upstream_http_Location $location{ # 這種方案是把全部到 8180 端口的重定向都改爲 80 端口,有必定的風險,容易誤傷 # ~http://(?<domains>.*):8180/(?<param>.*) http://$domains/$param; # 這種方案是針對特定域名 8180 端口的重定向,範圍可控,寫法冗長 ~http://test.snowheart.cn:8180/(?<param>.*) http://test.snowheart.cn/$param; # 默認狀況,保持原狀 default $upstream_http_Location; } server { location /app { proxy_pass http://192.168.36.72:7001/app; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_redirect off; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; more_set_headers -s '301 302' 'Location $location'; } }
$ curl http://test.snowheart.cn/app/RedirectServlet --dump - HTTP/1.1 302 Server: nginx/1.14.2 Date: Mon, 11 May 2020 16:41:23 GMT Content-Length: 0 Location: http://test.snowheart.cn/app/hello.html Connection: keep-alive
大坑
Nginx 須要安裝新的 module,這又涉及到從新編譯和 root 安裝等操做,在企業裏面,作這些是須要必定的流程和規範性評估的,故通過考慮後,放棄此方案。上述筆記僅做爲 POC 階段使用。
Nginx 方案受阻後,使用當前測試環境在用的 Apache 來實現 Location 的重寫
# httpd.conf # 打開 Rewrite 功能 RewriteEngine On # 對 Location 進行重寫 Header edit Location "(^http[s]?://test.snowheart.cn:8180/)" "/" Header edit Location "(^http[s]?://123.234.123.234:8180/)" "/"
$ curl http://test.snowheart.cn/app/RedirectServlet --dump - HTTP/1.1 302 Server: nginx/1.14.2 Date: Mon, 11 May 2020 16:41:23 GMT Content-Length: 0 Location: http://test.snowheart.cn/app/hello.html Connection: keep-alive
簡單的三行配置,即達成了咱們的目的。
本文由博客一文多發平臺 OpenWrite 發佈!