重写重定向以包括用于访问服务的端口
Rewriting redirects to include the port used to access the service
我有这样的设置:
使用我的 Vagrant 开发环境的用户在他们的主机上访问 localhost:8080
,该主机被转发到 Vagrant 到客户机上 localhost:80
的 NGINX 运行。一些请求被转发到我在 localhost:8080
的应用程序服务器 运行 上,还有一些是从 NGINX 提供的静态文件。
当我访问我的网站时发生了一件奇怪的事情。我有一个成功重定向的登录页面,并且 URL 从 http://localhost:8080/login
重写为 http://localhost:80/login
。
这是我的网站 NGINX 配置:
upstream appserver {
server 127.0.0.1:8080;
}
upstream production {
server www.mysite.com:443;
}
server {
listen 80 default_server;
server_name _;
client_max_body_size 20M;
access_log /var/log/nginx/project.access.log;
error_log /var/log/nginx/project.error.log;
index /index;
location ~ ^(/js/testpage.js) {
alias /vagrant/artifacts/www/js/testpage.js;
}
location ~ ^(/test/js/app.js) {
alias /vagrant/test/js/app.js;
}
location ~ /test/js/app_router.js {
alias /vagrant/test/js/app_router.js;
}
location ~ /test/js/app_layout_controller.js {
alias /vagrant/test/js/app_layout_controller.js;
}
location ~ /test/js/apps/navbar/sections/layout/navbar_layout_controller.js {
alias /vagrant/test/js/apps/navbar/sections/layout/navbar_layout_controller.js;
}
location ~ /test/js/apps/navbar/sections/navbar/navbar_options_view.js {
alias /vagrant/test/js/apps/navbar/sections/navbar/navbar_options_view.js;
}
location ~ /test/js/apps/navbar/sections/navbar_all_views.js {
alias /vagrant/test/js/apps/navbar/sections/navbar_all_views.js;
}
location ~ ^/test/js/apps/(.*/testpage_.*\.js)$ {
alias /vagrant/test/js/apps/;
}
location ~ ^/test/js/(.*)$ {
alias /vagrant/js/;
}
location ~ ^/build/js/(.*)$ {
alias /vagrant/artifacts/www/js/;
}
location ~ ^/build/css/(.*)$ {
alias /vagrant/artifacts/www/css/;
}
location ~ ^/(.*main.*)\.[@\-_\/\d\w]+\.(js|css)$ {
alias /vagrant/.;
}
location ~ ^/(css|js|fonts|favicon.ico) {
root /vagrant;
}
location ~ ^/receipts/js/(.*)$ {
alias /vagrant/receipts/js/;
}
location ~ ^/bower_components/(.*)$ {
alias /vagrant/bower_components/;
}
location ~ ^/login-promo/ {
access_log off;
proxy_pass https://production;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/(admin|login|logout|index|build|testpage|receipts|open|reset|resetpage|privacy|change|activeUser|personPrivacyAcceptances) {
access_log off;
proxy_pass http://appserver;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
我不确定重定向的实际来源,它可能来自应用程序服务器后端或前端 JavaScript。有没有一种方法可以确保所有重定向都采用访问客户端使用的端口?
更新:只需将 <a href="/login">login</a>
link 添加到根页面并尝试使用该 link 导航即可将我重定向到 http://localhost:80/login
而不是 http://localhost:8080/login
.
这可能是将来宾的 nginx 端口转发到主机上的另一个端口的不良副作用。
见http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
在最后一个位置块中停用代理重定向应该可以解决问题:
proxy_redirect off;
这可能是因为 port_in_redirect
默认为 on
。参见:http://wiki.nginx.org/HttpCoreModule#port_in_redirect
禁用它可能会消除一些关于为什么应用端口的混淆。
从那里开始,只需根据需要在代理传递重定向中设置适当的 host_port
或 remote_port
即可。通过查看您的配置,您似乎很乐意使用核心模块变量,包含这些变量将非常简单。
参见:
http://wiki.nginx.org/HttpCoreModule#.24remote_port
http://wiki.nginx.org/HttpCoreModule#.24server_port
这似乎是由于应用程序代码中的重定向错误造成的。
如果您的架构与上述类似并且遇到了问题,您遇到问题的原因很可能是因为在没有考虑 Host
header.
您的 nginx 应用程序看到这样的请求:
GET /path/to/resource
Host: virtualinstance:8888
不幸的是,当它构造重定向时,它做了一些愚蠢的事情并在不考虑 Host
header 的情况下重建重定向,而是选择它知道它正在使用的主机和端口.破坏我的重定向的代码看起来像这样:
return redirect("http://" + getHostName() + "/" + getPath())
首先,它对协议进行硬编码很糟糕,但更糟糕的是,它使用了一种无需考虑端口即可获取主机名的方法。这将 return 重定向到 http://localhost/path
,而不是 http://localhost:8888/path
。
开发人员,这就是为什么您应该始终使用 Host
header 作为重定向源的原因:
return redirect("%s://%s/%s" % (getProtocol(), getHeader("Host"),
getPath())
这会使用原始协议、来自 Host
的全文和路径进行合理的重定向。
我有这样的设置:
使用我的 Vagrant 开发环境的用户在他们的主机上访问 localhost:8080
,该主机被转发到 Vagrant 到客户机上 localhost:80
的 NGINX 运行。一些请求被转发到我在 localhost:8080
的应用程序服务器 运行 上,还有一些是从 NGINX 提供的静态文件。
当我访问我的网站时发生了一件奇怪的事情。我有一个成功重定向的登录页面,并且 URL 从 http://localhost:8080/login
重写为 http://localhost:80/login
。
这是我的网站 NGINX 配置:
upstream appserver {
server 127.0.0.1:8080;
}
upstream production {
server www.mysite.com:443;
}
server {
listen 80 default_server;
server_name _;
client_max_body_size 20M;
access_log /var/log/nginx/project.access.log;
error_log /var/log/nginx/project.error.log;
index /index;
location ~ ^(/js/testpage.js) {
alias /vagrant/artifacts/www/js/testpage.js;
}
location ~ ^(/test/js/app.js) {
alias /vagrant/test/js/app.js;
}
location ~ /test/js/app_router.js {
alias /vagrant/test/js/app_router.js;
}
location ~ /test/js/app_layout_controller.js {
alias /vagrant/test/js/app_layout_controller.js;
}
location ~ /test/js/apps/navbar/sections/layout/navbar_layout_controller.js {
alias /vagrant/test/js/apps/navbar/sections/layout/navbar_layout_controller.js;
}
location ~ /test/js/apps/navbar/sections/navbar/navbar_options_view.js {
alias /vagrant/test/js/apps/navbar/sections/navbar/navbar_options_view.js;
}
location ~ /test/js/apps/navbar/sections/navbar_all_views.js {
alias /vagrant/test/js/apps/navbar/sections/navbar_all_views.js;
}
location ~ ^/test/js/apps/(.*/testpage_.*\.js)$ {
alias /vagrant/test/js/apps/;
}
location ~ ^/test/js/(.*)$ {
alias /vagrant/js/;
}
location ~ ^/build/js/(.*)$ {
alias /vagrant/artifacts/www/js/;
}
location ~ ^/build/css/(.*)$ {
alias /vagrant/artifacts/www/css/;
}
location ~ ^/(.*main.*)\.[@\-_\/\d\w]+\.(js|css)$ {
alias /vagrant/.;
}
location ~ ^/(css|js|fonts|favicon.ico) {
root /vagrant;
}
location ~ ^/receipts/js/(.*)$ {
alias /vagrant/receipts/js/;
}
location ~ ^/bower_components/(.*)$ {
alias /vagrant/bower_components/;
}
location ~ ^/login-promo/ {
access_log off;
proxy_pass https://production;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/(admin|login|logout|index|build|testpage|receipts|open|reset|resetpage|privacy|change|activeUser|personPrivacyAcceptances) {
access_log off;
proxy_pass http://appserver;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
我不确定重定向的实际来源,它可能来自应用程序服务器后端或前端 JavaScript。有没有一种方法可以确保所有重定向都采用访问客户端使用的端口?
更新:只需将 <a href="/login">login</a>
link 添加到根页面并尝试使用该 link 导航即可将我重定向到 http://localhost:80/login
而不是 http://localhost:8080/login
.
这可能是将来宾的 nginx 端口转发到主机上的另一个端口的不良副作用。
见http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
在最后一个位置块中停用代理重定向应该可以解决问题:
proxy_redirect off;
这可能是因为 port_in_redirect
默认为 on
。参见:http://wiki.nginx.org/HttpCoreModule#port_in_redirect
禁用它可能会消除一些关于为什么应用端口的混淆。
从那里开始,只需根据需要在代理传递重定向中设置适当的 host_port
或 remote_port
即可。通过查看您的配置,您似乎很乐意使用核心模块变量,包含这些变量将非常简单。
参见:
http://wiki.nginx.org/HttpCoreModule#.24remote_port http://wiki.nginx.org/HttpCoreModule#.24server_port
这似乎是由于应用程序代码中的重定向错误造成的。
如果您的架构与上述类似并且遇到了问题,您遇到问题的原因很可能是因为在没有考虑 Host
header.
您的 nginx 应用程序看到这样的请求:
GET /path/to/resource
Host: virtualinstance:8888
不幸的是,当它构造重定向时,它做了一些愚蠢的事情并在不考虑 Host
header 的情况下重建重定向,而是选择它知道它正在使用的主机和端口.破坏我的重定向的代码看起来像这样:
return redirect("http://" + getHostName() + "/" + getPath())
首先,它对协议进行硬编码很糟糕,但更糟糕的是,它使用了一种无需考虑端口即可获取主机名的方法。这将 return 重定向到 http://localhost/path
,而不是 http://localhost:8888/path
。
开发人员,这就是为什么您应该始终使用 Host
header 作为重定向源的原因:
return redirect("%s://%s/%s" % (getProtocol(), getHeader("Host"),
getPath())
这会使用原始协议、来自 Host
的全文和路径进行合理的重定向。