Python 如何在 Tornado 中返回没有默认模板的 HTTP 错误代码?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13730945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 09:29:32  来源:igfitidea点击:

How do I return HTTP error code without default template in Tornado?

pythontornado

提问by S-K'

I am currently using the following to raise a HTTP bad request:

我目前正在使用以下内容来提出 HTTP 错误请求:

raise tornado.web.HTTPError(400)

which returns a html output:

它返回一个 html 输出:

<html><title>400: Bad Request</title><body>400: Bad Request</body></html>

Is it possible to return just the HTTP response code with a custom body?

是否可以仅返回带有自定义正文的 HTTP 响应代码?

采纳答案by VisioN

You may simulate RequestHandler.send_errormethod:

您可以模拟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>")

回答by Rod Hyde

Tornado calls RequestHandler.write_errorto output errors, so an alternative to VisioN's approachwould be override it as suggested by the Tornado docs. The advantage to this approach is that it will allow you to raise HTTPErroras before.

Tornado 调用RequestHandler.write_error输出错误,因此VisioN 方法的替代方法将按照 Tornado文档的建议覆盖它。这种方法的优点是它可以让你HTTPError像以前一样加注。

The source for RequestHandler.write_erroris here. Below you can see an example of a simple modification of write_error that will change the set the status code and change the output if you provide a reason in kwargs.

对于源RequestHandler.write_error在这里。下面您可以看到一个简单修改 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,
                })

回答by Somesh

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))

when ever self.send_error()call is initiated write_error()function is called by the request handler. So you can create your custom error data dict here and render it to your custom error page.

self.send_error()调用被启动时write_error()函数被请求处理程序调用。因此,您可以在此处创建自定义错误数据字典并将其呈现到您的自定义错误页面。

http.responses[status_code] returns the error code text like "page not found" based on the status code.

http.responses[status_code] 根据状态代码返回错误代码文本,如“找不到页面”。

回答by TIO

Also you can override get_error_htmlmethod in your handler. For example:

您也可以在处理程序中覆盖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):
...

回答by punkrockpolly

It's better to use the standard interface and define your custom message on the HTTPError.

最好使用标准接口并在HTTPError.

raise tornado.web.HTTPError(status_code=code, log_message=custom_msg)

You can then parse the error in your RequestHandlerand check for the message:

然后,您可以解析错误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>")

回答by scharfmn

This exchangeclarifies some of the approaches suggested here, and discounts the reasonkeyword (which I was thinking about trying).

这个交流澄清了这里建议的一些方法,并打折reason关键字(我正在考虑尝试)。

Q:(by mrtn)

问:(通过mrtn)

"I want to use raise tornado.web.HTTPError(400, reason='invalid request')to pass a custom reason to the error response, and I hope to do this by overriding the write_error (self, status_code, **kwargs)method.

“我想使用raise tornado.web.HTTPError(400, reason='invalid request')自定义原因传递给错误响应,我希望通过覆盖该write_error (self, status_code, **kwargs)方法来做到这一点。

"But it seems that I can only access self._reasoninside write_error, which is not what I want. I also tried kwargs['reason']but that does not exist."

“不过好像只能进入self._reason里面write_error,这不是我想要的。我也试过,kwargs['reason']但是不存在。”

A:(by Tornado lead developer @bendarnell)

答:(由 Tornado 首席开发人员 @bendarnell 提供)

"The exception that exposed the error is available to write_erroras an exc_infotriple in the keyword arguments. You can access the reason field with something like this:

“暴露错误的异常可write_error作为exc_info关键字参数中的三元组使用。您可以使用以下内容访问原因字段:

if "exc_info" in kwargs:
    e = kwargs["exc_info"][1]
    if isinstance(e, tornado.web.HTTPError):
        reason = e.reason

"But note that the reasonfield is essentially deprecated (it is not present in HTTP/2), so it's probably not the best way to do whatever you're trying to do here (HTTPError's log_messagefield is a little better, but still not ideal). Just raise your own exception instead of using HTTPError; your write_erroroverride can use self.set_status(400)when it sees the right kind of exception."

“但请注意,该reason字段基本上已被弃用(它不存在于 HTTP/2 中),因此它可能不是您在这里尝试做的任何事情的最佳方式(HTTPErrorlog_message字段好一点,但仍然不理想). 只需引发您自己的异常而不是使用HTTPError;当它看到正确的异常类型时,您的write_error覆盖可以使用self.set_status(400)。”

回答by Gosha null

For json error response i use follow template:

对于 json 错误响应,我使用以下模板:

Request handler:

请求处理程序:

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))

Errors handler:

错误处理程序:

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)