我有两个由Nginx提供服务的Express 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。我不必在应用程序中添加任何第三方模块,但是我希望有一个解决我问题的Nginx解决方案。
谢谢。
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'));
});
我通过结合安德鲁·拉弗斯的第一个解决方案解决了这个问题
location /admin/ {
proxy_pass https://127.0.0.1:3010/admin/;
}