简体   繁体   English

根据 Flask 中请求的内容类型更改响应

[英]Change response based on content type of request in Flask

I have a Flask application that returns both HTML pages and JSON responses to API requests.我有一个 Flask 应用程序,它返回 HTML 页面和对 API 请求的 JSON 响应。 I want to change what an error handler returns based on the content type of the request.我想根据请求的内容类型更改错误处理程序返回的内容。 If the client requests application/json , I want to return a jsonify response, otherwise I want to return a render_template response.如果客户端请求application/json ,我想返回一个jsonify响应,否则我想返回一个render_template响应。 How can I detect what was requested and change the response appropriately?如何检测请求的内容并适当地更改响应?

The current error handlers I have only return an HTML response.我当前的错误处理程序只返回一个 HTML 响应。

def register_errorhandlers(app):
    """Register error handlers."""
    def render_error(error):
        """Render error template."""
        # If a HTTPException, pull the `code` attribute; default to 500
        error_code = getattr(error, 'code', 500)
        return render_template('{0}.html'.format(error_code)), error_code
    for errcode in [401, 404, 500]:
        app.errorhandler(errcode)(render_error)

Use request.content_type to get the content type the client sent with the request.使用request.content_type获取客户端随请求发送的内容类型。 Use request.accept_mimetypes the get the mimetypes the client indicated it can accept in a response.使用request.accept_mimetypes获取客户端表示它可以在响应中接受的 mimetypes。 Use these to determine what to return.使用这些来确定要返回的内容。

from flask import request, jsonify, render_template

if request.accept_mimetypes.accept_json:
    return jsonify(...)
else:
    return render_template(...)

I used the after_request decorator to do this and checked the content type:我使用after_request装饰器来执行此操作并检查内容类型:

@app.after_request
def after_request_helper(resp):
    if resp.content_type == "text/html":
        # If a HTTPException, pull the `code` attribute; default to 500
        error_code = getattr(error, 'code', 500)
        return render_template('{0}.html'.format(error_code)), error_code
    else:
        return app.errorhandler(errcode)(render_error)

A more detailed answer:更详细的答案:

def wants_json_response():
    return request.accept_mimetypes['application/json'] >= \
    request.accept_mimetypes['text/html']

The wants_json_response() helper function compares the preference for JSON or HTML selected by the client in their list of preferred formats. wants_json_response()辅助函数比较客户端在其首选格式列表中选择的 JSON 或 HTML 的偏好。 If JSON rates higher than HTML, then it is necessary to return a JSON response.如果 JSON 速率高于 HTML,则有必要返回 JSON 响应。 Otherwise, return the original HTML responses based on templates.否则,返回基于模板的原始 HTML 响应。

For the JSON responses would slightly supplement the function with one condition: if wants_json_response(): which is what you need.对于 JSON 响应,该函数会稍微补充一个条件: if wants_json_response():这就是您所需要的。 So the answer is in that.所以答案就在于此。

If the condition is true we could write a function that would generate a response:如果条件为真,我们可以编写一个生成响应的函数:

def api_error_response(status_code, message=None):
    payload = {'error': HTTP_STATUS_CODES.get(status_code, 'Unknown error')}
    if message:
        payload['message'] = message
    response = jsonify(payload)
    response.status_code = status_code
    return response

This function uses the handy HTTP_STATUS_CODES dictionary from Werkzeug (a core dependency of Flask) that provides a short descriptive name for each HTTP status code.该函数使用 Werkzeug(Flask 的核心依赖项)提供的方便的HTTP_STATUS_CODES字典,该字典为每个 HTTP 状态代码提供了一个简短的描述性名称。 For easier and faster understanding, 'error' is used to represent errors, so you only need to worry about the numeric status code and the optional long description.为了更容易和更快的理解,'error'用来表示错误,所以你只需要担心数字状态码和可选的长描述。 The jsonify() function returns a Flask Response object with a default status code of 200, so after the response is created, it is necessary to set the status code to the correct one for the error. jsonify()函数返回一个 Flask Response 对象,默认状态码为 200,因此在创建响应后,需要为错误设置正确的状态码。

So if we put it all together now it would look like this:因此,如果我们现在将它们放在一起,它会如下所示:

# app/__init__.py
import requests

def register_errorhandlers(app):
    from .errors import render_error

    for e in [
        requests.codes.INTERNAL_SERVER_ERROR,
        requests.codes.NOT_FOUND,
        requests.codes.UNAUTHORIZED,
    ]:
        app.errorhandler(e)(render_error)

and

# app/errors.py
import requests

from flask import render_template, request, jsonify
from werkzeug.http import HTTP_STATUS_CODES

from .extensions import db


def api_error_response(status_code, message=None):
    payload = {'error': HTTP_STATUS_CODES.get(status_code, 'Unknown error')}
    if message:
        payload['message'] = message
    response = jsonify(payload)
    response.status_code = status_code
    return response


def wants_json_response():
    return request.accept_mimetypes['application/json'] >= \
    request.accept_mimetypes['text/html']


def render_error(e):
    if requests.codes.INTERNAL_SERVER_ERROR == e.code:
        db.session.rollback()
    if wants_json_response():
        return api_error_response(e.code)
    else:
        return render_template(f'{e.code}.html'), e.code

Additionally此外

Then they could use the response generation for other cases as well.然后他们也可以将响应生成用于其他情况。 The most common error that the API is going to return is going to be the code 400, which is the error for “bad request”. API 将返回的最常见错误将是代码 400,这是“错误请求”的错误。 This is the error that is used when the client sends a request that has invalid data in it.这是客户端发送包含无效数据的请求时使用的错误。

In order to generate messages to the function below even easier in these cases, we forward only the required description - message .为了在这些情况下更容易地为下面的函数生成消息,我们只转发所需的描述message

def bad_request(message):
    return api_error_response(400, message)

I hope this will help in approaching with errors :)我希望这将有助于解决错误:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 烧瓶中没有POST请求和Content-Type“application / json”的响应 - No response with POST request and Content-Type “application/json” in flask 如何根据Python Flask或Bottle框架中的内容类型将传入的请求有效载荷作为方法/函数参数解组 - How to unmarshall incoming request payload as method/function arguments based on content type in Python flask or bottle frameworks GET 请求不在 json 内容类型 flask - GET request not in json content type flask Flask请求和application / json内容类型 - Flask request and application/json content type 如何在flask-restful中自定义响应内容类型? - How to customize response content type in flask-restful? Flask-Restful 错误:请求 Content-Type 不是 'application/json'。"} - Flask-Restful Error: request Content-Type was not 'application/json'."} 如何基于html向Flask发送post请求<select>改变 - How to send a post request to Flask based on html <select> change 强制 Content-Type 或公开 Flask 中已知内容类型的 request.data - Force Content-Type or expose request.data in Flask for known content-type Flask 同时具有请求和响应的中间件 - Flask Middleware with both Request and Response 正确的方法来更改默认的响应内容类型 - Proper way to change the default Response content-type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM