如何使用反向代理处理 Express 应用程序中的重定向

Posted

技术标签:

【中文标题】如何使用反向代理处理 Express 应用程序中的重定向【英文标题】:How to handle redirects in Express application with Reverse Proxy 【发布时间】:2015-07-30 06:06:16 【问题描述】:

我有两个由 nginx 提供服务的 Express 驱动的 NodeJS 应用程序。一个应用程序是 RESTful API,由 Angular SPA 使用,另一个是管理门户。这是我想要在这里实现的目标:

location / 
  # Serves Client Side Angular Application


location /api 
  # Serves RESTful Application


location /admin 
  # Serves Admin Portal

这是我对 nginx 的完整配置:

server  
server_name localhost;
listen 80;
listen [::]:80;
index index.html;

location /  
    expires -1; 
    add_header Pragma "no-cache"; 
    add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"; 
    root /var/www/example/client/dist;
    try_files $uri $uri/ /index.html =404; 


location /admin/ 
    proxy_pass http://127.0.0.1:3010/;
    proxy_http_version 1.1;
    rewrite /admin/(.*) /$1 break;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host/admin/;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
 

location /api  
    proxy_pass http://127.0.0.1:3011;
    proxy_http_version 1.1;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;

 

这两个 NodeJS 应用程序都可以永久使用并在其定义的端口上完美运行。

我的管理应用程序面临的问题是,当我尝试点击http://example.com/admin 时,它会将我重定向到http://example.com/login,而它应该将我重定向到http://example.com/admin/login。我尝试通过向管理应用程序添加中间件来解决此问题,例如:

app.use('*', function (req, res, next) 
 if(process.env.target === 'dev')
   if(req.originalUrl.indexOf('/admin') > -1)
     res.redirect('/admin' + req.url);
   
   next();
 
);

但这不起作用。我应该如何处理这种情况?无论如何,nginx可以处理应用程序重定向吗?如果没有,我应该如何在不同环境(Dev、Staging、Prod 等)的应用程序中处理它?我正在使用 nginx 1.4.6、节点 0.12.2 和 express 4.12.2。如果我必须在我的应用程序中添加任何第 3 方模块,我没有任何问题,但如果我的问题有 nginx 解决方案,我更愿意。

谢谢。

【问题讨论】:

您尝试做的事情绝对是可行的。只是为了确认一下,您是否在两个单独的快速应用程序上提供托管端口 3010 和 3011? 你在向我们展示你完整的 nginx 配置吗?您在哪里为您的/* 路由配置proxy_pass,例如/login @AndrewLavers 是的。它们是两个独立的应用程序。这是我完整的 nginx 配置。我错过了什么? 【参考方案1】:

你的 nginx 配置的问题是 /admin 路由的重写:

rewrite /admin/(.*) /$1 break;

使用此规则,您的管理门户节点应用程序不知道其路径都托管在 /admin 根目录之外,因此如果您的应用程序执行重定向相对于它认为是根目录,例如 res.redirect('/login'),它将浏览器发送到localhost/login 是有道理的。

另一种方法是删除您的 nginx rewrite 并让管理员门户知道此 /admin 路径。这样,您可以选择重定向到 relative 路径,如下所示:res.redirect('login') 告诉 express 考虑当前请求的路径。您可以使用express.Router 使这个更清洁,例如:

var adminRoutes = express.Router()
    .get('/', function(req, res) 
        if(!req.user) 
            // Will redirect to /admin/login
            res.redirect('login');
         else 
            res.send('Hello');
        
    )
    .get('/login', login);

// Tell express to host all routes above under a common /admin root
app.use('/admin', adminRoutes);

另一方面,如果有更好的理由让您必须重写 nginx,则您始终可以为所有应用程序的重定向手动添加 /admin 根目录。您可以通过从proxy_set_header 设置的自定义标头中读取此挂载路径来临时附加此挂载路径。例如:

app.use(function(req, res, next) 
    res.mountedAt = req.headers['X-Mounted-At'];
    next();
);

app.get('/', function(req, res) 
    res.redirect(path.join(res.mountedAt, '/login'));
);

【讨论】:

删除重定向指令对我不起作用。对于您提供的最后一个选项,我是否必须在重定向用户的任何地方使用res.redirect(path.join(res.mountedAt, '/login')); 如果您要重定向到位于 /admin 下的另一个管理页面,可以。 这是否解决了您的问题?我处于类似的情况,我的 nginx 反向代理将所有 /app 请求发送到我的 nodejs 应用程序。问题在于,一旦在浏览器中加载了 Angular Index 和 core.js,对 nodejs REST API 的调用就会缺少 nginx 路由请求所需的 /app/ 前缀。我刚刚得到一个Cannot GET /api/endpoint,它应该是/app/api/endpoint 有人知道解决办法吗?我也有同样的情况。【参考方案2】:

我通过将 Andrew Lavers 的第一个解决方案与

结合起来解决了这个问题
        location /admin/ 
        proxy_pass          https://127.0.0.1:3010/admin/;
    

【讨论】:

以上是关于如何使用反向代理处理 Express 应用程序中的重定向的主要内容,如果未能解决你的问题,请参考以下文章

express反向代理

IIS Express 可以支持反向代理吗?

反向代理 后端处理

Node.js - 使用 Express 和 http-proxy 进行反向代理

text 反向代理使用后端NodeJS Express创建React App Build

带有 Express 和 nginx 反向代理的 Vue Router 历史模式