当存在路由匹配但没有HTTP方法匹配时,从express.js发送405

当存在路由匹配但没有HTTP方法匹配时,从express.js发送405,express,Express,我正在寻找一种干净的方法,如果客户端发送的请求与映射的url路由匹配,但与映射的HTTP方法不匹配,则不允许使用我的express app return 405方法 我当前的实现是有一个默认的“catch all”处理程序,该处理程序尝试将url与注册路由相匹配,而忽略HTTP方法。如果存在匹配项,则我们知道返回405,否则我们让express执行其默认的404行为 我希望有一种更好的方法,不需要运行所有的路由匹配两次(一次由express运行,一次由我的处理程序运行)。由于模糊性,实在没有其他

我正在寻找一种干净的方法,如果客户端发送的请求与映射的url路由匹配,但与映射的HTTP方法不匹配,则不允许使用我的express app return 405方法

我当前的实现是有一个默认的“catch all”处理程序,该处理程序尝试将url与注册路由相匹配,而忽略HTTP方法。如果存在匹配项,则我们知道返回405,否则我们让express执行其默认的404行为


我希望有一种更好的方法,不需要运行所有的路由匹配两次(一次由express运行,一次由我的处理程序运行)。

由于模糊性,实在没有其他方法。就我个人而言,我会这样做:

var route = '/page/:id/comments'
app.get(route, getComments)
app.all(route, send405)

function send405(req, res, next) {
  var err = new Error()
  err.status = 405
  next(err)
}

无论哪种方式,您都必须检查两次路由。

以下是我在多个Django应用程序中成功使用的方法,现在在Node和Express中使用。下面还介绍了关于HTTP 405的以下内容:

响应必须包括一个Allow标头,其中包含一个有效响应列表 请求的资源的方法

因此,关键点是将请求路由到同一个处理程序,而不考虑方法

app.all('/page/:id', page.page);
app.all('/page/:id/comments', page.comments);
app.all('/page/:id/attachments', page.attachments);
...
下一点是验证处理程序函数“comments”中的方法。请注意,处理程序负责处理所有方法。在Django的世界中,这是唯一的方法,因为框架迫使您将URL的路由与对URL所代表的资源执行的实际操作分开

在处理程序中,您可以检查如下方法

exports.comments = function (req, res) {
    if (req.route.method === 'get') {
        res.send(200, 'Hello universe.');
    } else {
        res.set('Allow', 'GET');
        res.send(405, 'Method Not Allowed');
    }
}
…但正如您所预料的那样,代码将很快变得重复且不好读,特别是当您有许多处理程序函数和许多不同的允许方法集时

因此,我为该作业准备了一个名为restful的快捷函数。在任何需要的地方定义函数。我个人会把它放在helpers.js中,放在实现处理函数的同一目录下

var restful = function (req, res, handlers) {
    // 
    // This shortcut function responses with HTTP 405
    // to the requests having a method that does not
    // have corresponding request handler. For example
    // if a resource allows only GET and POST requests
    // then PUT, DELETE, etc requests will be responsed
    // with the 405. HTTP 405 is required to have Allow
    // header set to a list of allowed methods so in
    // this case the response has "Allow: GET, POST" in
    // its headers [1].
    // 
    // Example usage
    //     
    //     A handler that allows only GET requests and returns
    //     
    //     exports.myrestfulhandler = function (req, res) {
    //         restful(req, res, {
    //             get: function (req, res) {
    //                 res.send(200, 'Hello restful world.');
    //             }
    //         });
    //     }
    // 
    // References
    //     
    //     [1] RFC-2616, 10.4.6 405 Method Not Allowed
    //     https://tools.ietf.org/html/rfc2616#page-66
    //     
    //     [2] Express.js request method
    //     http://expressjs.com/api.html#req.route
    //
    var method = req.route.method; // [2]
    if (!(method in handlers)) {
        res.set('Allow', Object.keys(handlers).join(', ').toUpperCase());
        res.send(405);
    } else {
        handlers[method](req, res);
    }
}
使用restful,现在自动处理405个响应并设置适当的Allow头非常轻松。只需为您允许的每个方法提供一个函数,其余的由restful完成

因此,让我们修改前面的示例:

exports.comments = function (req, res) {
    restful(req, res, {
        get: function (req, res) {
            res.send(200, 'Hello restful universe.');
        }
    });
}
为什么叫restful?在web中,API必须遵守一些约定,如使用HTTP 405响应具有不受支持方法的请求。在需要时,这些约定中的许多可以集成到restful中。因此,名称是restful,而不是类似于auto405或http405handler的名称


希望这有帮助。有什么想法吗?

这是一个老问题,但我是这么做的。我只是把它放在我所有的路线之后,但在我的400处理器之前

// Handle 405 errors
app.use(function(req, res, next) {
  var flag = false;
  for (var i = 0; i < req.route.stack.length; i++) {
    if (req.method == req.route.stack[i].method) {
      flag = true;
    }
  }
  if (!flag) {
    err = new Error('Method Not Allowed')
    err.status = 405;
    return next(err)
  }

  next();
});
//处理405个错误
应用程序使用(功能(请求、恢复、下一步){
var标志=假;
对于(变量i=0;i
方法1:使用
.route()
.all()
//您的路由处理程序
const handlers=require(`./handlers.js`);
//405处理器
const methodNotAllowed=(req,res,next)=>res.status(405.send();
路由器
.路线(`/products`)
.get(handlers.getProduct)
.put(handlers.addProduct)

.所有(不允许使用的方法)我一直这样做:

假设您有
/
的GET和POST方法处理程序。您可以使用
app.route
router.route
包装路径,并相应地分配处理程序

    app.route("/").get((req, res) => {
            /* DO SOMETHING*/
    }).post((req, res) => {
            /* DO SOMETHING*/
    }).all((req, res) => {
            res.status(405).send();
    });
请求将与路由匹配,并通过处理程序进行过滤。如果存在处理程序,它将像往常一样得到处理。否则,它将到达将状态代码设置为405并结束请求的
all
处理程序

我是这样修复的:

/*paths here*/

router.get('/blah/path1', blah.do_something );
router.post('/blah/path2', blah.do_something_else );

/* if we get here we haven't already gone off down another path */

router.all('/*', (req,res) => { res.status(405), 
   res.json({'status':405,
             'message':req.method + ' not allowed on this route'}) 
});

/* simples */

谢谢,你的建议很有意义,而且比我现在做的要好。这个解决方案不是可行的。关于HTTP 405说:“响应必须包含一个Allow标头,其中包含请求资源的有效方法列表。”解决方案无法提供该列表,因此不应视为有效。检查我的答案,寻找更合适的方法。似乎是烘焙框架本身的最佳选择。为了让它在Express 4中工作,我必须更改
var method=req.route.method
var方法=(req.method | |“”).toLowerCase()
Express不推荐的res.send(status,body):使用res.status(status).send(body)代替,但是为什么不使用
.all()
?和
Allow
标题也应该有
标题,因为我相信这只适用于较旧版本的Express。现在路由方法大不相同了。HTTP 405响应必须有
Allow
头。如何区分404和405。这解决了一个问题,但产生了一个更大的问题作为副作用。这些示例中的任何一个的可能重复实际上都无效,因为具有405状态的响应必须具有带有允许方法的标题“Accept”。