【问题标题】:ExpressJS, route handling with two routers that also use each other?ExpressJS,使用两个也相互使用的路由器进行路由处理?
【发布时间】:2017-10-23 21:12:10
【问题描述】:

我想为这些示例路由创建路由处理:

GET /users
GET /users/:userid
GET /users/:userid/groups
GET /users/:userid/groups/:groupid

GET /groups
GET /groups/:groupid
GET /groups/:groupid/users
GET /groups/:groupid/users/:userid

此设置的人为代码示例。想象一个目录结构为:

# index.js
# routes/users.js
# routes/groups.js
# lib/users.js
# lib/groups.js

以及每个存在的内容:

index.js

express = require 'express'
UsersRouter = require './routes/users'
GroupsRouter = require './routes/groups'

app = express()

app.use '/users', UsersRouter
app.use '/groups', GroupsRouter

app.use (err, req, res, next) -> res.sendStatus(404)

app.listen '3000', () ->
    console.log "Listening on port #{3000}"

module.exports = app

routes/users.js

express = require 'express'
Users = require '../lib/users'
GroupsRouter = require './groups'

router = express.Router()

router.param 'userid', (req, res, next, userid) ->
    req.userid = userid
    next()

router.get '/', (req, res) ->
    Users.list req, (err, users) ->
        return next err if err
        res.status(200).send(users)

router.get '/:userid', (req, res, next) ->
    Users.find req, (err, user) ->
        return next err if err
        res.status(200).send(user)

router.use '/:userid/groups', GroupsRouter

module.exports = router

routes/groups.js

express = require 'express'
Groups = require '../lib/groups'
UsersRouter = require './users'

router = express.Router()

router.param 'groupid', (req, res, next, groupid) ->
    req.groupid = groupid
    next()

router.get '/', (req, res, next) ->
    Groups.list req, (err, groups) ->
        return next err if err
        res.status(200).send(groups)

router.get '/:groupid', (req, res, next) ->
    Groups.find req, (err, group) ->
        return next err if err
        res.status(200).send(group)

router.use '/:groupid/users', UsersRouter

module.exports = router

lib/users.js

module.exports =
    list: (req, cb) ->
        if req.groupid
            return cb null, "List of all users in group #{req.groupid}"
        else
            return cb null, "List of all users"

    find: (req, cb) ->
        if req.groupid and req.userid
            return cb null, "User #{req.userid} if in #{req.groupid}"
        else
            return cb null, "The user #{req.userid}"

lib/groups.js

module.exports =
    list: (req, cb) ->
        if req.userid
            return cb null, "List of all groups for #{req.userid}"
        else
            return cb null, "List of all groups"

    find: (req, cb) ->
        if req.userid and req.groupid
            return cb null, "Group #{req.groupid} if it has member #{req.userid}"
        else
            return cb null, "The group #{req.groupid}"

问题是,我收到了一个 espress.js 错误,因为我执行了路由器的周期性要求。有可能吗?

如果我只是在另一个路由器中包含一个路由器,而不是相反,它会从我的请求中获得预期的响应。

一个较长的路由用例示例,假设我想查看一个组中是否有用户,如果有,则返回该用户所属的所有其他组:

GET /groups/:groupid/users/:userid/groups

我收到的错误:

TypeError: Router.use() requires middleware function but got a Object

【问题讨论】:

  • 您的组/用户文件中有什么?一个函数?您必须将函数传递给 router.use,例如如果您导出的组/用户文件中有一个函数 routing(),您将传递 Groups.routing 或调用它, function(req, res, next){ Groups.routing(req, res, next); }
  • 两个路由器看起来非常相似:express = require('express'); Users = require('../users'); router = express.Router(); router.get('/', function(req, res, next){}); router.get('/:groupid', function(req, res, next){}); router.use('/:groupid/users', Users); module.exports = router; 还要注意 - 如果我没有周期性要求 - 就像 - 我使用 users 分组路由而不是 groups 路由在用户中,expressjs 处理得很好。
  • 要求递归是行不通的。不过,您提供的错误消息并没有说明这一点。它更多的是错误的参数错误。因为您传递的不是函数,而是对象(路由器)
  • 这听起来你需要将公共共享代码分解为共享函数并将它们放在自己的模块中,然后你的其他两个模块都可以加载共享模块并使用这些函数。使用 Express 编程时,人们似乎只将路由视为可共享单元,但您可以创建多个路由使用的通用函数,并将这些函数放在自己的模块中。
  • @jfriend00,/users 中调用的代码是Users.list(req, cb) 方法。 /users/:userid 只需调用 Users.find(req, cb)。与组路由相同(好吧,他们会调用Groups.list/find)。因此,如果路由是/users/:userid/groups,我想调用/groups 调用的相同方法,在这种情况下Groups.list(req, cb) 过滤具有成员:userid 的组列表。 /groups/:groupid/users 也一样,我希望它调用 /users 调用的相同共享代码,属于 :groupid 的用户列表。

标签: node.js express


【解决方案1】:

users.js 依赖于groups.js,但随后groups.js 在执行时需要users.js。这意味着它将进入一个循环:

users.js 呼叫groups.js

groups.js 调用 users.js,后者调用 groups.js 等等。

【讨论】:

    【解决方案2】:

    这是解决这种循环情况的可能方法

    将处理程序代码保存在单独的模块中,并在路由模块中重复使用。 (这也是jfriend00 在 cmets 中试图提出的观点)

    例如。

    // userHandler.js
    
    module.exports = {
      browse: (req, res) => {
        // return user list
      },
      find: (req, res) => {
        // return user
      }
    }
    
    
    // userRouter
    // ... 
    const handler = require('userHandler');
    router.get('/', handler.browse);
    // ...
    
    // groupsRouter
    // ... 
    const uHandler = require('userHandler');
    router.get('/:groupid/users', uHandler.browse);
    router.get('/:groupid/users/:userid', uHandler.find);
    // ...
    

    【讨论】:

      【解决方案3】:

      我能够通过从一个路由器导出中间件路由来实现我想要的路由,我可以将其分配给我想在另一个路由器中匹配的路由。

      routes/users.js

      express = require 'express'
      Users = require '../lib/users'
      
      router = express.Router()
      
      router.param 'userid', (req, res, next, userid) ->
          req.userid = userid
          next()
      
      router.pseudo = router.use (req, res, next) -> next()
      
      router.get '/', (req, res) ->
          Users.list req, (err, users) ->
              return next err if err
              res.status(200).send(users)
      
      router.get '/:userid', (req, res, next) ->
          Users.find req, (err, user) ->
              return next err if err
              res.status(200).send(user)
      
      module.exports = router
      
      router.use '/:userid/groups', (require '../groups').pseudo
      

      routes/groups.js

      express = require 'express'
      Groups = require '../lib/groups'
      
      router = express.Router()
      
      router.param 'groupid', (req, res, next, groupid) ->
          req.groupid = groupid
          next()
      
      router.pseudo = router.use (req, res, next) -> next()
      
      router.get '/', (req, res, next) ->
          Groups.list req, (err, groups) ->
              return next err if err
              res.status(200).send(groups)
      
      router.get '/:groupid', (req, res, next) ->
          Groups.find req, (err, group) ->
              return next err if err
              res.status(200).send(group)
      
      module.exports = router
      
      router.use '/:groupid/users', (require '../users).pseudo
      

      此路由设置允许以下请求:

      GET /groups/:groupid/users
      

      路由会从组路由中间件设置req.groupid值,然后路由到用户/路由,列出用户。

      如果您继续以菊花链方式将它们连接起来,则相同:

      GET /groups/:groupid/users/:userid/groups
      

      路由将首先访问组,然后是用户,然后返回组,并为我提供 req.groupid 和 req.userid 的设置值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-30
        相关资源
        最近更新 更多