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

Pau*_*tum 16 express

如果客户端发送的请求与映射的URL路由匹配但与映射的HTTP方法不匹配,我正在寻找一种干净的方法让我的快速应用程序返回405方法不允许.

我当前的实现是有一个默认的"catch-all"处理程序,它尝试将url与寄存器路由匹配,忽略HTTP方法.如果有匹配,那么我们知道返回405,否则我们让快递做其默认的404行为.

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

Aks*_*lén 19

这是一种方法,我成功地使用了多个Django应用程序,现在使用Node和Express.RFC 2616(HTTP/1.1)也遵循以下关于HTTP 405的内容:

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

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

app.all('/page/:id', page.page);
app.all('/page/:id/comments', page.comments);
app.all('/page/:id/attachments', page.attachments);
...
Run Code Online (Sandbox Code Playgroud)

下一步是在处理函数'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');
    }
}
Run Code Online (Sandbox Code Playgroud)

...但正如您所期望的那样,代码将很快变得重复并且不易阅读,尤其是当您有许多处理函数和许多不同的允许方法集时.

因此,我为该作业准备了一个名为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

通过restful,现在可以自动处理405响应并且设置了正确的Allow标头.只要给每个你允许和方法的功能,宁静没有休息.

所以我们修改前面的例子:

exports.comments = function (req, res) {
    restful(req, res, {
        get: function (req, res) {
            res.send(200, 'Hello restful universe.');
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

这个名字为何宁静?在RESTful Web中,API必须遵守诸如使用HTTP 405对具有不受支持的方法的请求进行响应的约定.许多这些公约可以被集成到宁静的需要的时候.因此,名称是宁静的,而不是像auto405http405handler.

希望这可以帮助.有什么想法吗?


dwh*_*ieb 10

方法一:使用.route().all()

// Your route handlers
const handlers = require(`./handlers.js`);

// The 405 handler
const methodNotAllowed = (req, res, next) => res.status(405).send();

router
.route(`/products`)
.get(handlers.getProduct)
.put(handlers.addProduct)
.all(methodNotAllowed);
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为请求是按照它们附加到路由的顺序(请求“瀑布”)传递给处理程序的。该.get().put()处理程序将赶上GET和PUT请求,其余的都将落空的.all()处理程序。

方法二:中间件

创建中间件,检查允许的方法,如果方法未列入白名单,则返回 405 错误。这种方法很好,因为它允许您查看和设置每个路由的允许方法以及路由本身。

这是methods.js中间件:

const methods = (methods = ['GET']) => (req, res, next) => {
  if (methods.includes(req.method)) return next();
  res.error(405, `The ${req.method} method for the "${req.originalUrl}" route is not supported.`);
};

module.exports = methods;
Run Code Online (Sandbox Code Playgroud)

然后,您将methods在您的路线中使用中间件,如下所示:

const handlers = require(`./handlers.js`); // route handlers
const methods = require(`./methods.js`);   // methods middleware

// allows only GET or PUT requests
router.all(`/products`, methods([`GET`, `PUT`]), handlers.products);

// defaults to allowing GET requests only
router.all(`/products`, methods(), handlers.products);
Run Code Online (Sandbox Code Playgroud)

  • 这些示例实际上都不是有效的,因为具有 405 状态的响应必须具有带有允许的方法的标头“Accept”。 (3认同)

Jon*_*Ong 2

由于模棱两可,确实没有其他办法。就我个人而言,我会做这样的事情:

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)
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这个解决方案不是可行的方法。[RFC 2616 (HTTP/1.1)](https://tools.ietf.org/html/rfc2616#page-66) 关于 HTTP 405 的规定:“响应必须包含一个允许标头,其中包含所请求的有效方法列表资源”。该解决方案无法提供该列表,因此不应被视为有效。检查我的答案以获得更合适的方法。 (7认同)