我目前正在使用以下内容来引发 HTTP 错误请求:
raise tornado.web.HTTPError(400)
它返回一个 html 输出:
<html><title>400: Bad Request</title><body>400: Bad Request</body></html>
是否可以只返回带有自定义正文的 HTTP 响应代码?
您可以模拟RequestHandler.send_error
方法:
class MyHandler(tornado.web.RequestHandler):
def get(self):
self.clear()
self.set_status(400)
self.finish("<html><body>My custom body</body></html>")
Tornado 调用RequestHandler.write_error
输出错误,因此VisioN 方法的替代方案将按照 Tornado文档的建议覆盖它。这种方法的优点是它可以让你HTTPError
像以前一样加注。
的来源RequestHandler.write_error
是here。下面您可以看到一个简单修改 write_error 的示例,如果您在 kwargs 中提供原因,它将更改设置状态代码并更改输出。
def write_error(self, status_code, **kwargs):
if self.settings.get("serve_traceback") and "exc_info" in kwargs:
# in debug mode, try to send a traceback
self.set_header('Content-Type', 'text/plain')
for line in traceback.format_exception(*kwargs["exc_info"]):
self.write(line)
self.finish()
else:
self.set_status(status_code)
if kwargs['reason']:
self.finish(kwargs['reason'])
else:
self.finish("<html><title>%(code)d: %(message)s</title>"
"<body>%(code)d: %(message)s</body></html>" % {
"code": status_code,
"message": self._reason,
})
最好使用标准接口并在HTTPError
.
raise tornado.web.HTTPError(status_code=code, log_message=custom_msg)
然后,您可以解析您的错误RequestHandler
并检查消息:
class CustomHandler(tornado.web.RequestHandler):
def write_error(self, status_code, **kwargs):
err_cls, err, traceback = kwargs['exc_info']
if err.log_message and err.log_message.startswith(custom_msg):
self.write("<html><body><h1>Here be dragons</h1></body></html>")
def write_error(self, status_code, **kwargs):
#Function to display custom error page defined in the handler.
#Over written from base handler.
data = {}
data['code'] = status_code
data['message'] = httplib.responses[status_code]
# your other conditions here to create data dict
self.write(TEMPLATES.load('error.html').generate(data=data))
当self.send_error()调用被发起时 write_error()函数被请求处理程序调用。因此,您可以在此处创建自定义错误数据字典并将其呈现到您的自定义错误页面。
http.responses[status_code] 根据状态代码返回错误代码文本,如“找不到页面”。
您也可以在处理程序中覆盖get_error_html方法。例如:
import tornado.web
class CustomHandler(tornado.web.RequestHandler):
def get_error_html(self, status_code, **kwargs);
self.write("<html><body><h1>404!</h1></body></html>")
...
def get(self):
...
这个交流澄清了这里建议的一些方法,并打折reason
关键字(我正在考虑尝试)。
问:(由mrtn)
“我想用raise tornado.web.HTTPError(400, reason='invalid request')
一个自定义原因来传递错误响应,我希望通过重写write_error (self, status_code, **kwargs)
方法来做到这一点。
“不过好像只能进入self._reason
里面write_error
,不是我想要的,我也试过kwargs['reason']
了,不存在。”
答:(由 Tornado 首席开发人员 @bendarnell 提供)
“暴露错误的异常write_error
可用作关键字参数中的exc_info
三元组。您可以使用以下内容访问原因字段:
if "exc_info" in kwargs:
e = kwargs["exc_info"][1]
if isinstance(e, tornado.web.HTTPError):
reason = e.reason
“但请注意,该reason
字段基本上已被弃用(它不存在于 HTTP/2 中),因此它可能不是执行您在此处尝试执行的任何操作的最佳方式(HTTPError
的log_message
字段稍微好一点,但仍然不理想). 只需引发您自己的异常,而不是使用HTTPError
;当它看到正确的异常类型时,您的write_error
覆盖可以使用。self.set_status(400)
对于 json 错误响应,我使用以下模板:
请求处理程序:
import json
from tornado.web import RequestHandler
from src.lib.errors import HTTPBadRequest
class JsonHandler(RequestHandler):
def prepare(self):
content_type = ''
if "Content-Type" in self.request.headers:
content_type = self.request.headers['Content-Type']
if content_type == 'application/json':
try:
self.request.body = json.loads(self.request.body.decode('utf-8'))
except ValueError:
raise HTTPBadRequest
def write_error(self, *args, **kwargs):
err_cls, err, traceback = kwargs['exc_info']
self.set_status(err.status_code)
if err.description:
self.write_json(err.description)
self.finish()
def set_default_headers(self):
self.set_header('Content-Type', 'application/json')
def write_json(self, response):
self.write(json.dumps(response))
错误处理程序:
from typing import Any
from tornado import httputil
class BaseHTTPError(Exception):
def __init__(
self, status_code: int = 500, description=None, *args: Any, **kwargs: Any
) -> None:
if description is None:
description = {}
self.status_code = status_code
self.description = description
self.args = args
self.kwargs = kwargs
def __str__(self) -> str:
message = "HTTP %d: %s" % (
self.status_code,
httputil.responses.get(self.status_code, "Unknown"),
)
return message
class HTTPBadRequest(BaseHTTPError):
def __init__(self, *args, **kwargs):
super().__init__(status_code=400, description={"error": "Bad Request"}, *args, **kwargs)