web-dev-qa-db-fra.com

Est-il possible de définir une URL de base pour l'application NodeJS?

Je veux pouvoir héberger plusieurs applications NodeJS sous le même domaine, sans utiliser de sous-domaines (comme google.com/reader au lieu d'images.google.com). Le problème est que je tape toujours la première partie de l'url, par ex. "/ reader" dans Express/NodeJS.

Comment puis-je configurer une application Express pour que l'URL de base soit something.com/myapp?

Donc au lieu de:

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

Je peux faire:

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

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

J'aimerais également configurer staticProvider de Connect pour qu'il se comporte de la même manière (en ce moment, il sert par défaut à servir des fichiers statiques à something.com/js ou something.com/css au lieu de something.com/myapp/js)

58
David Tang

Pour le moment, cela n'est pas pris en charge et il n'est pas facile de l'ajouter par vous-même.

Tout le matériel de routage est enfoui profondément dans le code du serveur, et en prime, il n'y a aucune exposition des itinéraires eux-mêmes.

J'ai fouillé la source et j'ai également vérifié la dernière version d'Express et du middleware Connect, mais il n'y a toujours pas de support pour une telle fonctionnalité, vous devriez ouvrir un problème soit sur Connect ou Express lui-même.

Pendant ce temps ...

Patchez la chose vous-même, voici un moyen rapide et facile avec une seule ligne de code modifiée.

Dans ~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js, rechercher:

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

Cela devrait être autour de la ligne 357, remplacez-le par:

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

Maintenant, ajoutez simplement le paramètre:

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

Cela fonctionne bien avec des chemins qui sont des chaînes simples, pour le support RegEx, vous devrez pirater vous-même le middleware du routeur, mieux vaut déposer un problème dans ce cas.

En ce qui concerne le fournisseur statique, ajoutez simplement /mypapp lors de la configuration.

Mise à jour

A fait fonctionner aussi avec 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;
    }
}

J'ai seulement testé cela avec une poignée d'expressions, donc ce n'est pas testé à 100% mais en théorie, cela devrait fonctionner.

Mise à jour 2

Dépôt d'un problème avec le patch:
https://github.com/visionmedia/express/issues/issue/478

16
Ivo Wetzel

Le routeur express peut gérer cela depuis 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);

Réponse précédente (avant express 4.0):

Le module express-namespace (mort maintenant) faisait l'affaire:

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
        });
});
128
Remi Mélisson

Juste pour mettre à jour le fil, maintenant avec Express.jsv4 vous pouvez le faire sans utiliser 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);

À votre santé!

8
danilodeveloper

J'ai pu y parvenir en utilisant une combinaison d'espace de noms express pour les itinéraires et un correctif de la discussion de groupe Google ci-dessous pour les actifs statiques. Cet extrait traitera une demande adressée à /foo/javascripts/jquery.js comme une demande adressée à /javascripts/jquery.js:

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

Source: https://groups.google.com/forum/#!msg/express-js/xlP6_DX6he0/6OTY4hwfV-0J

7
Ben Zittlau

Il existe également des problèmes de fiabilité. Si la fiabilité est importante, une solution courante consiste à utiliser un proxy HTTP inverse frontal tel que nginx ou HAProxy. Ils utilisent tous les deux une architecture événementielle à un seul thread et sont donc très évolutifs.

Ensuite, vous pouvez avoir différents processus de nœud pour différents sous-sites, et si un site échoue (exception non interceptée, fuite de mémoire, erreur de programmeur, peu importe), les autres sous-sites continuent de fonctionner.

3
nponeccop

Je cherchais cette fonctionnalité mais des routes API, pas des fichiers statiques. Ce que j'ai fait, c'est que lorsque j'ai initialisé le routeur, j'ai ajouté le chemin de montage. Donc ma configuration ressemble à ceci

//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, {});
    });
});

Remarquez le '/ api' lors de l'appel du routeur

2
Xerri

Je sais que c'est une très vieille question, mais Express a beaucoup changé depuis que la plupart de ces réponses ont été publiées, alors j'ai pensé partager mon approche.

Vous pouvez bien sûr utiliser des routeurs avec Express 4 pour regrouper les fonctionnalités associées derrière un chemin particulier. Ceci est bien documenté et a déjà été couvert par d'autres réponses.

Cependant, il est également possible de monter une application entière sur un chemin particulier. Par exemple, supposons que notre application (celle que nous voulons héberger à /myapp) ressemble à ceci, dans un fichier appelé 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;

Dans notre fichier js principal, nous pourrions alors monter toute cette application sur le chemin /myapp:

var express = require('express'),
    app = express(),
    myApp = require('./myapp').app;

app.use('/myapp', myApp);

app.listen(3000);

Notez que nous avons créé deux applications ici, l'une montée sur l'autre. L'application principale pourrait avoir d'autres sous-applications montées sur différents chemins selon les besoins.

Le code dans myapp.js est complètement indépendant de l'endroit où il a été monté. Il est similaire à la structure utilisée par le express-generator à cet égard.

Une documentation sur les sous-applications peut être trouvée ici:

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

1
skirtle