如何在Node.js和Express 4中分离路由?

85

我想将路由从我的server.js文件中分离出来。

我正在按照Scotch.io上的教程进行操作。 http://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4

如果所有行都在server.js文件中,它可以工作。但是我无法将其分离。我该如何让它工作?

server.js

// set up ======================================================================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');

// configuration ===============================================================
app.use(bodyParser());

var port = process.env.PORT || 8000;

var mongoose = require('mongoose');
var database = require('./config/database');
mongoose.connect(database.url);
var Video = require('./app/models/video');

// routes =======================================================================
app.use('/api', require('./app/routes/routes').router);

// listen (start app with node server.js) ======================================
app.listen(port);
console.log("ready captain, on deck" + port);

module.exports = app;

还有 app/routes/routes.js 文件

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

router.use(function(req, res, next) {
  console.log('Something is happening.');
  next();
});

router.get('/', function(req, res) {
  res.json({ message: 'hooray! welcome to our rest video api!' });  
});


router.route('/videos')

  .post(function(req, res) {

    var video = new Video();
    video.title = req.body.title;

    video.save(function(err) {
  if (err)
    res.send(err);

  res.json({ message: 'Video criado!' });
});


  })

  .get(function(req, res) {
    Video.find(function(err, videos) {
      if (err)
        res.send(err);

      res.json(videos);
    });
  });

module.exports.router = router;

嗨@bbuecherl,我遇到了一个ReferenceError:Video未定义的错误。 - yellowbuck
@bbuecherl 我试过了,但它找不到模块... Ben,在 server.js 上全部代码都能正常工作... - yellowbuck
1
在 route.js 中引入 video.js 时,使用正确的路径,例如 "..\models\video"。 - Kiran Pagar
请查看此示例http://wiki.workassis.com/nodejs-express-separate-routes,以制作单独的路由文件。 - Bikesh M
这个回答解决了你的问题吗?如何在Express中将路由处理程序包含在多个文件中? - ggorlen
显示剩余4条评论
9个回答

105

Server.js

var express = require('express');
var app = express();

app.use(express.static('public'));

//Routes
app.use(require('./routes'));  //http://127.0.0.1:8000/    http://127.0.0.1:8000/about

//app.use("/user",require('./routes'));  //http://127.0.0.1:8000/user  http://127.0.0.1:8000/user/about


var server = app.listen(8000, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("Example app listening at http://%s:%s", host, port)

})

路由.js

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

//Middle ware that is specific to this router
router.use(function timeLog(req, res, next) {
  console.log('Time: ', Date.now());
  next();
});


// Define the home page route
router.get('/', function(req, res) {
  res.send('home page');
});

// Define the about route
router.get('/about', function(req, res) {
  res.send('About us');
});


module.exports = router;

*在routs.js中,您应该定义中间件

参考http://wiki.workassis.com/nodejs-express-separate-routes/


1
当我有更多的路由时,这个答案如何扩展?@Bikesh - Calvintwr
使用这种方法时,我注意到我的req.body返回undefined,在将其放回index.js后,body出现了。有什么想法吗? - S.B.
@Calvintwr 只需创建更多带有不同路由的文件(routes2.js等)。 - theknightD2
1
@theknightD2 我一点也不建议这样做。 - Calvintwr

70

就将路由从主文件中分离而言...

Server.js

//include the routes file
var routes = require('./routes/route');
var users = require('./routes/users');
var someapi = require('./routes/1/someapi');

////////
app.use('/', routes);
app.use('/users', users);
app.use('/1/someapi', someapi);

路由/route.js

//last line - try this
module.exports = router;

对于新项目,您也可以尝试使用命令行

express project_name

你需要使用 express-generator 完成这个任务。


2
这并没有真正分离路由,而是分离了控制器。@Bikesh 的解决方案更正确。 - superluminary
我正在尝试将API与主应用程序文件分离,但出现错误。`apiRoutes.post('/register', function(req, res, next) { ^TypeError: 无法读取未定义属性'post' at Object.<anonymous> (F:\saurabh_sharma\nodejs\salecrm\app\routes.js:4:10) at Module._compile (module.js:413:34) at Object.Module._extensions..js (module.js:422:10) ...` - Saurabh Sharma
啊,我明白了,我认为我可以使用fs来得到最佳解决方案。 - Taufik Nurhidayat

24

使用Express 4.0将路由分离到单独的文件中的另一种方法:

server.js

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

routes.js

module.exports = (function() {
    'use strict';
    var router = require('express').Router();

    router.get('/', function(req, res) {
        res.json({'foo':'bar'});
    });

    return router;
})();

为什么在函数内部使用 'use strict'; - basickarl
@KarlMorrison 我想这只是为了满足代码检查工具。 - kriskodzi
11
将整个路由定义包装在*(function() { ... })()*结构中的好处是什么? - Sylvain Leroux
8
@SylvainLeroux - Node 具有文件级别的变量作用域,因此我认为在这种情况下使用 IIFE 没有任何好处。应该把它删除。请注意,这里只翻译内容,不提供其他信息或解释。 - superluminary
我在使用app.use('/', routes)时遇到了问题,所以我只能使用app.use(routes)。我的所有路由都只是命中router.get('/')。 - stealthysnacks

14

将路由分离到自己的文件中的一种方法。

SERVER.JS

var routes = require('./app/routes/routes');  //module you want to include
var app=express();
routes(app);   //routes shall use Express

ROUTES.JS

module.exports=function(app) {
 //place your routes in here..
 app.post('/api/..., function(req, res) {.....}   //example
}

7
我不太喜欢到处传递app。这不是一个整洁的解决方案。 - superluminary

6
如果你正在使用TypeScript和ES6与express-4.x,那么这将是最好的模板; src/api/login.ts
import express, { Router, Request, Response } from "express";

const router: Router = express.Router();
// POST /user/signin
router.post('/signin', async (req: Request, res: Response) => {
    try {
        res.send('OK');
    } catch (e) {
        res.status(500).send(e.toString());
    }
});

export default router;

src/app.ts

import express, { Request, Response } from "express";
import compression from "compression";  // compresses requests
import expressValidator from "express-validator";
import bodyParser from "body-parser";
import login from './api/login';

const app = express();

app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());

app.get('/public/hc', (req: Request, res: Response) => {
  res.send('OK');
});

app.use('/user', login);

app.listen(8080, () => {
    console.log("Press CTRL-C to stop\n");
});

使用 constexport 的代码更加明确可靠。

3

我们只需要两行代码

简述

$ npm install express-routemagic --save

const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')

就是这样!

更多信息:

你会如何做到这一点?让我们从文件结构开始:

project_folder
|--- routes
|     |--- api
|           |--- videos
|           |     |--- index.js
|           |
|           |--- index.js
|     
|--- server.js

请注意,路由下有一个结构。Route Magic是文件夹感知的,并且会自动将其隐含为API URI结构。

在server.js中

只需要两行代码:

const magic = require('express-routemagic')
magic.use(app, __dirname, 'routes')

在routes/api/index.js文件中
const router = require('express').Router()

router.get('/', (req, res) => { 
    res.json({ message: 'hooray! welcome to our rest video api!' })
})

在routes/api/videos/index.js文件中

Route Magic会识别您的文件夹结构并为您的API设置相同的结构,因此此URL将是api/videos

const router = require('express').Router()

router.post('/', (req, res) => { /* post the video */ })
router.get('/', (req, res) => { /* get the video */ })

声明:本人编写了该软件包。但实际上,这是早该有的东西,我已经达到无法等待其他人编写的极限。


2

我遇到的问题是,当使用router.use方法时,尝试在这些方法中记录路径会产生问题。最终,我使用了以下方法来解决问题。它让你可以在更高的层次保留低级路由器的路径。

routes.js

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

var posts = require('./posts');

router.use(posts('/posts'));  

module.exports = router;

posts.js

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

let routeBuilder = path => {

  router.get(`${path}`, (req, res) => {
    res.send(`${path} is the path to posts`);
  });

  return router

}

module.exports = routeBuilder;

如果您记录路由器堆栈,实际上可以看到路径和方法。


1
我只是在server.js文件中声明了这些文件,并使用require。
 app.use(express.json());
 require('./app/routes/devotion.route')(app);
 require('./app/routes/user.route')(app);

0
在我的情况下,我喜欢尽可能多地使用Typescript。以下是我如何使用类组织我的路由:
export default class AuthService {
    constructor() {
    }

    public login(): RequestHandler {
       return this.loginUserFunc;
    }

    private loginUserFunc(req: Request, res: Response): void {
        User.findOne({ email: req.body.email }, (err: any, user: IUser) => {
            if (err)
                throw err;
            if(!user)
                return res.status(403).send(AuthService.noSuccessObject());
            else
                return AuthService.comparePassword(user, req, res);
        })
    }
}

从您的 server.js 或者您的服务器代码所在位置,您可以按照以下方式调用 AuthService:

import * as express from "express";
import AuthService from "./backend/services/AuthService";

export default class ServerApp {
    private authService: AuthService;

    this.authService = new AuthService();

    this.myExpressServer.post("/api/login", this.authService.login(), (req: express.Request, res: express.Response) => {
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接