【问题标题】:Breaking out express routes into separate files将快速路线分解为单独的文件
【发布时间】:2016-03-23 10:51:17
【问题描述】:

我已经尝试了我在 s/o 上找到的所有答案,我确信我一定遗漏了一些东西。什么对我没有错误反而给了我 404。我尝试了来自Organize routes in Node.js 的答案,strongloop 的route-separation 模式,来自How to include route handlers in multiple files in Express? 的答案,遇到了与Router.use requires middleware function? 类似的错误,但这些答案都没有奏效. Unable to Split Routes into Separate Files in Express 4.0 的答案不会出错,但也会出现 404s。似乎每个答案都有不同的语法和风格,也许是我混合和匹配不正确?

现在我的 /routes/persons.js 有这个模式:

    var express = require('express');
    var persons = express.Router();

    persons.route('/persons/:user_id')
        .put(function (req, res, next) {
            // etc
    });

    module.exports = persons;       

在我的 server.js 文件中,我有:

    var persons = require('./routes/persons');
    app.use('/persons', persons);

这种组合不会引发错误,但它也不会做任何事情。我尝试将端点添加到 server.js 行:

    var persons = require('./routes/persons');
    app.get('/persons/:user_id', persons.addpersons);

将 people.js 剥离为仅导出函数:

    exports.addpersons = function (req, res, next) {
            var list = req.body;
            // etc
    }

还有一些变体,例如将整个 person.js 文件包装在 module.exports = function() 中,在末尾粘贴 module.exports = router,使用 app 而不是 router 等。

我忽略了什么?我应该添加一些其他中间件,重新安排我调用端点的方式,使用应用程序,还是坚持使用 router.route?当没有错误但端点仍然是 404 时,最可能的罪魁祸首是什么?

非常感谢!

============= 已编辑以包含 SERVER.JS =============

由于很明显有些地方设置错误,这里是我的 server.js 文件:

        var express = require('express');
        var app = express();
        var methodOverride = require('method-override');
        var mongoose = require('mongoose');
        var bodyParser = require('body-parser');
        var router = express.Router();
        var jwt    = require('jsonwebtoken');
        var config = require('./config');
        var nodemailer = require('nodemailer');
        var bcrypt = require('bcrypt-nodejs');
        var crypto = require('crypto');
        var async = require('async');

        var transporter = nodemailer.createTransport({
            service: 'gmail',
            auth: {
                user: 'email@gmail.com',
                pass: 'password'
            }
        });

        // I don't know if both are necessary, used multiple conflicting tutorials
        app.use(require('express-session')({
            secret: 'secret',
            resave: false,
            saveUninitialized: false
        }));
        app.set('superSecret', config.secret);

        var Schema = mongoose.Schema,
            Person = require('./models/person.js'),
            User = require('./models/user.js'),
            Event = require('./models/event.js');

        var port = process.env.PORT || 8080;
        mongoose.connect(config.database);

        app.use(bodyParser.json());
        app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
        app.use(bodyParser.urlencoded({ extended: true }));
        app.use(methodOverride('X-HTTP-Method-Override'));
        app.use(express.static(__dirname + '/public'));

        // routes go here

        app.use('/api', router);
        app.listen(port);
        console.log('gogogo port ' + port);

我不知道我还能在哪里寻找为什么包含路线需要打破常规模式。我的配置文件?我的过程文件?这些是服务器上唯一的其他文件,不包括 /models 和 /routes。

【问题讨论】:

  • 试试app.use('/persons/*', persons);
  • 没有错误,但仍然是 404'd。 :(
  • 我在下面看到您有拼写错误,这解决了问题吗?否则我会调查并弄清楚。
  • 不,错字是我复制后编辑的,而不是原件中的问题。我希望这很容易!当我从stackoverflow.com/questions/23923365/… 问题中添加 router.use '发生了什么事' 部分时,这确实有效!它仍然不会读取其余部分,但这至少告诉我文件正在加载,我想。

标签: javascript node.js express


【解决方案1】:

这里的关键是要了解app.use()对你的req对象做了什么(特别是对req.path),app.get()和朋友有什么不同,Express如何包装path-to-regexp(它的内部路径匹配模块)来处理路由。

1) app.use(path, middleware) 挂载中间件。在挂载的中间件/路由器内部,req.path 是相对于挂载路径的。只有请求路径的开头需要匹配,因此/foo 将适用于/foo(相对路径将为/)、/foo/bar(相对路径为/bar)等处的请求。

app.use(function (req, res, next) {
    console.log('Main: %s %s', req.method, req.path);
    next();
});

app.use('/foo', function (req, res) {
    console.log('In /foo: %s %s', req.method, req.path);
    res.send('Got there');
});

尝试运行上述设置,导航至localhost/foo 并查看以下日志:

Main: GET /foo
In /foo: GET /

2) app.get(path, middleware)app.post(path, middleware)不挂载目标中间件,所以req.path 被保留。 req.path 必须与您定义路由的整个模式匹配,因此 /foo 仅适用于 /foo 请求。

app.use(function (req, res, next) {
    console.log('Main: %s %s', req.method, req.path);
    next();
});

app.get('/foo', function (req, res) {
    console.log('In /foo: %s %s', req.method, req.path);
    res.send('Got there');
});

导航到localhost/foo 并查看:

Main: GET /foo
In /foo: GET /foo

3) app.route(path),如 Express 文档中所述,只是为了方便定义多个 app.get(middleware)app.post(middleware) 等共享同一个 path


现在,在您的情况下,这是一个工作设置:

主要

var persons = require('./routes/persons');
app.use('/persons', persons);

routes/persons.js

var router = require('express').Router();
router.route('/:user_id')
  .post(function (req, res) {
    // handle potato data
  })
  .get(function (req, res) {
    // get and send potato data
  });

module.exports = router;

这很方便,因为您只需在主文件中设置一次 /persons 入口点,因此您可以在以后根据需要轻松更新它(您也可以从配置文件中导入该路径值,从您的路由器对象或其他任何东西,Node 在这方面非常灵活)。 persons 路由器本身负责它的业务控制器,无论它具体安装在哪里。

【讨论】:

  • 我不得不重新添加猫鼬,这样它才能识别 Persons 的架构,但其余的我仍然喜欢你的例子。我在服务器控制台中没有收到任何错误,但浏览器说它是 404,并且页面是空白的。我真的很欣赏这个解释,但我不知道为什么它不起作用,也不知道可能的罪魁祸首(某处发生冲突?依赖?我不知道)。不过谢谢!
  • 刚刚在一个虚拟项目中尝试了这个设置,它对我来说很好用。我假设你有你的中间件发送一些数据?如果这种情况仍然存在,请在您的应用程序/中间件的某些部分尝试console.log,以查看您的请求被路由到的位置。
  • 我毫不怀疑您的版本可以正常工作,我只是不知道为什么我不能让它工作。我确实有我的 server.js console.logged 在其生命的一英寸内,这就是我知道在 server.js 中执行 app.get 并在 /routes 文件中执行 router.use 的原因,但如果我尝试这样做,我会出错然后点击 route.anything-else。这就是为什么我怀疑它一定是冲突,或者是 server.js 中早期的东西引入的怪癖。将编辑问题以包含该问题,以便您查看。
【解决方案2】:

我想通了!

当然,这可能是完全错误的方法(如果是,请告诉我)但它有效。

在我的 server.js 文件中,我有:

    var persons = require('./routes/persons');
    router.get('/persons/:user_id', persons);
    router.post('/persons/:user_id', persons);

我的 persons.js 文件现在看起来像这样:

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

    var Schema = mongoose.Schema,
        Person = require('../models/person.js');

    router.post('/persons/:user_id', function (req, res) {
        var potatoBag = req.body;
        Person.collection.insert(potatoBag, function onInsert(err, potatoBag) {
            if (err) {
                return res.json(err);
            } else {
                res.status(200).end();
            }
        });
    });

    router.get('/persons/:user_id', function(req, res) {
        var id = req.params.user_id;
        Person.find({'user_id':id},function(err, person) {
            if (err)
                return res.json(err);
            res.send(person);
        });
    });

    module.exports = router;

这似乎比大多数示例开销更大,但可能是因为 a) 使用 router.route 和 b) 使用导入的模式?我也有(req, res, next) 在那里,直到我删除了next 块。可能还是有点尴尬,但是,嘿,它的工作。谢谢大家的帮助!

【讨论】:

    【解决方案3】:

    而不是

    persons.route('/persons/:user_id')
        .put(function (req, res, next) {
            // etc
    });
    

    做:

    persons.put('/persons/:user_id',function (req, res, next) {
      // etc
    });
    

    【讨论】:

    • 实际上,我已经尝试过两种方式,因为我在其他各种答案中都看到了这两种模式。似乎可以解决问题的方法是将 server.js 中的 app.get 更改为 router.get ,然后突然间一切正常。我不知道为什么,因为我没有在任何答案中看到这种模式,但它有效,所以...... :)
    猜你喜欢
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 2018-06-24
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    相关资源
    最近更新 更多