如何定义Node.js应用程序上下文路径

How to define Node.js application context path?

本文关键字:js 应用程序 上下文 路径 Node 何定义 定义      更新时间:2023-09-26

来自Java世界,其中基于servlet的应用程序上下文路径是基于WAR文件名设置的,我试图理解在Node.js中定义上下文路径的最佳实践。

所讨论的Node应用程序没有在代码中定义上下文路径。例如,Express代码假设获取故事的请求具有路径为/story/1的URL。因此,JavaScript UI代码将向http://host:port/story/1发出请求。同样地,用户要连接到主应用程序页面,他们将访问http://host:port/。

我想将用户看到的URL更改为http://host:port/myapp。问题是如何一致地将"myapp"定义为应用程序上下文。我正在考虑的选项:

  • 在Express.js代码中定义上下文。
  • 在Nginx代理服务器中定义上下文

我如何确保用户总是在URL中看到"myapp"?我还需要重新映射所有的内部请求(那些由UI代码)也有'/myapp'上下文?

使用Nginx似乎更干净,因为它不需要更改代码。但是,这个目标可以通过Nginx配置单独实现吗?如果可以,如何实现?

由于这是一个常见的问题,因此必须有一个定义良好的模式来解决它。

正如你所说,最好在nginx配置中这样做,以便于上下文路径独立于应用程序代码。

在nginx端,你可以用location指令设置上下文路径,然后你可以从path中删除context path并将请求发送给应用程序。它可以通过nginx的重写指令来完成,如下所示:

    location /myapp/ {
        rewrite ^/myapp/(.*)$ /$1 break;
        ...
    }

因此,在nodejs (express)端,你应该假设应用程序运行在根路径(/)下。

你可以使用express router。

const express = require('express');
const app = express();
const http = require('http');
const httpServer = http.createServer(app);
const router = express.Router();
const contextPath = '/api';
router.get('/', function(req, res) {
  res.send("you've reached the API endpoint");
});
app.use(contextPath, router);
httpsServer.listen(9000));

host:9000/api/的get请求现在将返回"您已到达api端点"

实际上有很多方法可以将上下文路径添加到现有的express应用程序中。其中一种方法是利用http.createServer()。在下面的代码中,我添加了2个带有上下文路径的应用程序和一个备用应用程序。

const http = require('http');
const express = require('express');
const printReq = req => `contextPath: ${req.theContextPath},  url: ${req.url},  originalUrl ${req.theOriginalUrl}`;
//  Your original app
const app = express();
app.get('/hello', (req, res) => res.send(`Hello original, ${printReq(req)}`))
app.get('*', (req, res) => res.send(`Default original app routing , ${printReq(req)}`))
// second app with context /app1
const app1 = express();
const contextPath1 = '/app1'
app1.get('/hello', (req, res) => res.send(`Hello app1, ${printReq(req)}`))
app1.get('*', (req, res) => res.send(`Default app1 routing, ${printReq(req)}`))
// third app with context /app2
const app2 = express();
const contextPath2 = '/app2'
app2.get('/hello', (req, res) => res.send(`Hello app2, ${printReq(req)}`))
app2.get('*', (req, res) => res.send(`Default app2 routing, ${printReq(req)}`))
const stripContextPath = (req, contextPath) => {
  req.theOriginalUrl=req.url;
  req.theContextPath=contextPath;
  req.url = req.url.replace(new RegExp('^' + contextPath), '');
}
// -----------------------------------------------------------------------------------------------------------
// create raw server
const server = http.createServer((req, res) => {
  if(req.url.startsWith(contextPath1)){
    stripContextPath(req, contextPath1);
    app1(req, res);
  }else if(req.url.startsWith(contextPath2)){
    stripContextPath(req, contextPath2);
    app2(req, res);
  }else{
    // fallback
    app(req, res);
  }
});
server.listen(3000, '0.0.0.0', () => console.log('server listening at', server.address()));

你可以在保存为server.js并安装express dependency后做一些测试。

顺便说一句,如果你想用代理来做,除了nginx,你还可以使用节点http代理来给你现有的应用程序提供上下文路径