重写重定向以包括用于访问服务的端口

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_portremote_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 的全文和路径进行合理的重定向。