如果客户端发送的请求与映射的url路由匹配但与映射的HTTP方法不匹配,我正在寻找一种干净的方法让我的快速应用程序返回405方法不允许。
我当前的实现是拥有一个默认的“catch-all”处理程序,它尝试将url与寄存器路由匹配,忽略HTTP方法。如果有匹配,那么我们知道返回405,否则我们让快递做其默认的404行为。
我希望有一种更好的方法,不涉及两次运行所有路线匹配(一次是快递,一次是我的处理程序)。
答案 0 :(得分:17)
这是一种方法,我成功地使用了多个Django应用程序,现在使用Node和Express。关于HTTP 405,还有以下RFC 2616 (HTTP/1.1)说明:
响应必须包含一个包含有效列表的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 ?在RESTful web中,API必须遵守诸如使用HTTP 405对具有不支持方法的请求进行响应的约定。其中许多约定可以在需要时集成到 restful 。因此,名称是 restful ,而不是 auto405 或 http405handler 。
希望这会有所帮助。有什么想法吗?
答案 1 :(得分: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)
}
无论哪种方式,你都必须检查路线两次。
答案 2 :(得分:2)
.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);
这是有效的,因为请求按照它们附加到路由的顺序(请求“瀑布”)传递给处理程序。 .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;
然后,您将在路线中使用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);
答案 3 :(得分:1)
有点老问题,但这是我做的。我只是在我的所有路线之后,但在我的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();
});
答案 4 :(得分:1)
我一直这样做:
假设你有/
的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();
});
请求将与路由匹配并通过处理程序进行过滤。如果存在处理程序,它将照常处理。否则,它将到达all
处理程序,该处理程序将状态代码设置为405并结束请求。
答案 5 :(得分:0)
我这样修好了:
/*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 */