是否可以为NodeJS应用程序设置基本URL?

时间:2010-12-07 10:20:21

标签: node.js connect express

我希望能够在同一个域下托管多个NodeJS应用,而无需使用子域(例如google.com/reader而非images.google.com)。问题是我总是输入网址的第一部分,例如Express / NodeJS中的“/ reader”。

如何设置Express应用以使基本网址为something.com/myapp

所以而不是:

app.get("/myapp", function (req, res) {
   // can be accessed from something.com/myapp
});

我能做到:

// Some set-up
app.base = "/myapp"

app.get("/", function (req, res) {
   // can still be accessed from something.com/myapp
});

我还想将Connect的staticProvider配置为以相同的方式运行(现在它默认为将静态文件提供给something.com/jssomething.com/css而不是something.com/myapp/js

7 个答案:

答案 0 :(得分:126)

快递路由器可以自4.0起处理这个问题

http://expressjs.com/en/api.html#router

http://bulkan-evcimen.com/using_express_router_instead_of_express_namespace.html

var express = require('express');
var app = express();
var router = express.Router();

// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function(req, res, next) {
  console.log('%s %s %s', req.method, req.url, req.path);
  next();
});

// this will only be invoked if the path ends in /bar
router.use('/bar', function(req, res, next) {
  // ... maybe some additional /bar logging ...
  next();
});

// always invoked
router.use(function(req, res, next) {
  res.send('Hello World');
});

app.use('/foo', router);

app.listen(3000);

上一个答案(快递4.0之前):

快速命名空间模块(现在已经死了)用来做技巧:

https://github.com/visionmedia/express-namespace

require('express-namespace');

app.namespace('/myapp', function() {
        app.get('/', function (req, res) {
           // can be accessed from something.com/myapp
        });
});

答案 1 :(得分:16)

目前不支持此功能,并且要自行添加它并不容易。

整个路由的东西都埋藏在服务器代码的深处,作为奖励,没有他们自己的路线暴露。

我挖掘了源代码并检查了最新版本的Express和Connect中间件,但仍然不支持此类功能,您应该在ConnectExpress本身上打开一个问题

<强>同时...

自己修补这个问题,这里只需更改一行代码即可快速简便地使用。

~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js中,搜索:

// Generate the route
this.routes[method](path, fn);

这应该在第357行左右,将其替换为:

// Generate the route
this.routes[method](((self.settings.base || '') + path), fn);

现在只需添加设置:

app.set('base', '/myapp');

这适用于普通字符串的路径,对于RegEx支持,您必须自己在路由器中间件中进行破解,在这种情况下更好地提出问题。

就静态提供者而言,只需在设置时添加/mypapp即可。

<强>更新

也使用RegExp:

// replace
this.routes[method](baseRoute(self.settings.base || '', path), fn);

// helper
function baseRoute(base, path) {
    if (path instanceof RegExp) {
        var exp = RegExp(path).toString().slice(1, -1);
        return new RegExp(exp[0] === '^' ? '^' + base + exp.substring(1) : base + exp);

    } else {
        return (base || '') + path;
    }
}

我只用一些表达式对此进行了测试,所以这不是100%经过测试,但从理论上说它应该可以工作。

更新2

提出补丁问题:
https://github.com/visionmedia/express/issues/issue/478

答案 2 :(得分:8)

只是更新帖子,现在使用Express.js v4 ,您可以不使用express-namespace来执行此操作:

var express = require('express'),
    forumRouter = express.Router(),
    threadRouter = express.Router(),
    app = express();

forumRouter.get('/:id)', function(req, res){
  res.send('GET forum ' + req.params.id);
});

forumRouter.get('/:id/edit', function(req, res){
  res.send('GET forum ' + req.params.id + ' edit page');
});


forumRouter.delete('/:id', function(req, res){
  res.send('DELETE forum ' + req.params.id);
});

app.use('/forum', forumRouter);

threadRouter.get('/:id/thread/:tid', function(req, res){
  res.send('GET forum ' + req.params.id + ' thread ' + req.params.tid);
});

forumRouter.use('/', threadRouter);

app.listen(app.get("port") || 3000);

干杯!

答案 3 :(得分:6)

我能够使用针对路线的快速命名空间和针对静态资产的以下谷歌小组讨论的修复来实现此目的。这个片段会将请求处理到/foo/javascripts/jquery.js,就像对/javascripts/jquery.js的请求一样:

app.use('/foo', express.static(__dirname + '/public'));

<强>来源: https://groups.google.com/forum/#!msg/express-js/xlP6_DX6he0/6OTY4hwfV-0J

答案 4 :(得分:3)

还存在可靠性问题。如果可靠性很重要,通常的解决方案是使用前端反向HTTP代理,如nginx或HAProxy。它们都使用单线程统一架构,因此具有很高的可扩展性。

然后,您可以为不同的子网站提供不同的节点进程,如果一个站点出现故障(未捕获的异常,内存泄漏,程序员错误,无论如何),其余的子站点将继续工作。

答案 5 :(得分:2)

我一直在寻找这个功能,但是对于API路由,而不是静态文件。我做的是当我初始化路由器时,我添加了挂载路径。所以我的配置看起来像这样

//Default configuration
app.configure(function(){
    app.use(express.compress());
    app.use(express.logger('dev'));
    app.set('json spaces',0);
    app.use(express.limit('2mb'));
    app.use(express.bodyParser());

    app.use('/api', app.router);        // <---

    app.use(function(err, req, res, callback){
        res.json(err.code, {});
    });
});

调用路由器时注意'/ api'

答案 6 :(得分:1)

我知道这是一个非常古老的问题,但由于大多数这些答案都已发布,因此Express发生了很大变化,因此我认为我会分享我的方法。

当然,您可以使用带有Express 4的路由器将特定路径后面的相关功能组合在一起。这是有据可查的,已经被其他答案所涵盖。

但是,也可以在特定路径上安装整个应用程序。例如,让我们假设我们的应用程序(我们要在myapp.js托管的应用程序)看起来像这样,在一个名为var express = require('express'), path = require('path'), app = express(); app.use(express.static(path.join(__dirname, 'public'))); app.get('/hello', function(req, res) { res.send('Hello'); }); // Lots of other stuff here exports.app = app; 的文件中:

/myapp

在我们的主js文件中,我们可以在路径var express = require('express'), app = express(), myApp = require('./myapp').app; app.use('/myapp', myApp); app.listen(3000);

上安装整个应用程序
myapp.js

请注意,我们在这里创建了两个应用程序,一个安装在另一个上。主应用程序可以根据需要在不同路径上安装更多子应用程序。

express-generator中的代码完全独立于安装位置。它与{{1}}在这方面使用的结构相似。

有关子应用程序的一些文档可以在这里找到:

https://expressjs.com/en/4x/api.html#app.mountpath https://expressjs.com/en/4x/api.html#app.onmount