一个处理程序可以同时处理 post 并在龙卷风中获取不同的 URL
Can one handler handle both post and get with different URLs in tornado
一个处理程序可以同时处理 post 和获取 tornado 中的请求(URL 略有不同)吗?
例如我想要:
/app/user (POST)
使用请求中的数据创建新用户
正文
/app/user/<user_id> (GET)
到 return 给定 id 的用户
目前我有两个处理程序 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
一个处理程序可以同时处理 post 和获取 tornado 中的请求(URL 略有不同)吗?
例如我想要:
/app/user (POST)
使用请求中的数据创建新用户 正文/app/user/<user_id> (GET)
到 return 给定 id 的用户
目前我有两个处理程序 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