如何使用反向代理处理 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 应用程序中的重定向的主要内容,如果未能解决你的问题,请参考以下文章
Node.js - 使用 Express 和 http-proxy 进行反向代理