一个处理程序可以同时处理 post 并在龙卷风中获取不同的 URL

Can one handler handle both post and get with different URLs in tornado

一个处理程序可以同时处理 post 和获取 tornado 中的请求(URL 略有不同)吗?

例如我想要:

目前我有两个处理程序 GetUser & PostUser 和两个路由。

是的,您可以这样做,但是,到目前为止,我所看到的所有快速解决方案在处理位置参数时总是会带来一些小的不便。看看这个例子:

import tornado.ioloop
import tornado.web

class UserHandler(tornado.web.RequestHandler):
    def get(self, __):
        self.write("Get request")

    def post(self, user_id):
        self.write(f"Post request for user id {user_id}")

app = tornado.web.Application([
    (r"/app/user/?(\d+)?", UserHandler),
])

app.listen(8000)
tornado.ioloop.IOLoop.current().start()

这将构建一个匹配 url 模式并分配 UserHandler 的路由规则。 url 中的捕获组是可选的,因此当 POST 请求发送到 /app/user 时,None 可能会作为 user_id 传递。使用这种方法,tornado 将始终使用正则表达式中第二组的参数调用 get 方法。根据你的项目,你可能想要做更广泛的错误检查(检查给定的参数,如果它不是 None,发送一个 405 Method Not Allowed 或任何适合你的情况 - 也许你想要允许单个用户使用 GET?)


也可以通过添加两个具有相同处理程序的规则来实现:

import tornado.ioloop
import tornado.web

class UserHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Get request")

    def post(self, user_id):
        self.write(f"Post request for user id {user_id}")

app = tornado.web.Application([
    (r"/app/user", UserHandler),
    (r"/app/user/(\d+)", UserHandler),
])
app.listen(8000)
tornado.ioloop.IOLoop.current().start()

请记住,这两条路线都将匹配 POST 和 tornado 的 GET 请求,从而导致这种不便:

  • 如果有人向 /app/user 发送 POST 请求,它会抛出一个 TypeError: post() missing 1 required positional argument: 'user_id'.
  • 如果有人向 /app/user/123 发送 GET 请求,它会抛出 TypeError: get() takes 1 positional argument but 2 were given

您可以解决这些问题,但我认为第一个解决方案以更简洁的方式解决了这个问题。


编辑:当然,你也可以实现自己的Matcher class,它不仅可以区分urls,还可以通过sub[=51区分请求方法=]ing tornado.routing.PathMatches - 不过代码有点多。这里的主要缺点是对于有效的路由,服务器会在应该是405s的地方return 404响应(由于路由/"resource"本身是有效的,只是方法不对而已)

import tornado.ioloop
import tornado.web
import tornado.routing

class MethodAndPathMatch(tornado.routing.PathMatches):
    def __init__(self, method, path_pattern):
        super().__init__(path_pattern)
        self.method = method

    def match(self, request):
        if request.method != self.method:
            return None

        return super().match(request)

class UserHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Get request")

    def post(self, user_id):
        self.write(f"Post request for user id {user_id}")

app = tornado.web.Application([
    (MethodAndPathMatch("GET", r"/app/user"), UserHandler),
    (MethodAndPathMatch("POST", r"/app/user/(\d+)"), UserHandler),
])

app.listen(8000)
tornado.ioloop.IOLoop.current().start()

用于测试的 cURL 调用:

$ curl -w '\n' -X POST localhost:8000/app/user
$ curl -w '\n' -X POST localhost:8000/app/user/123
$ curl -w '\n' -X GET localhost:8000/app/user
$ curl -w '\n' -X GET localhost:8000/app/user/123

简单

def options(self):
    return
get=head=post=delete=patch=put=options