根据Flask中的Accept报头路由请求 [英] Route requests based on the Accept header in Flask

查看:198
本文介绍了根据Flask中的Accept报头路由请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想基于Accept HTTP标头路由到其他Flask视图,例如:

I would like to route to a different Flask views based on the Accept HTTP header, for example:

@api.route('/test', accept='text/html')
def test_html():
    return "<html><body>Test</body></html>"

@api.route('/test', accept='text/json')
def test_json():
    return jsonify(test="Test")

我没有在 Werkzeug规则构造函数中找到相关选项

I haven't found relevant option in Werkzeug Rule constructor, which is used by Flask. Is it a missing feature or is it possible to achieve the same effect differently, for example by intercepting and modifying URL path before routing?

我不想将视图合并为一个视图,因为这将使代码显着复杂化,其中有很多视图并且它们位于不同的蓝图中.

I don't want to merge the views into one because it would complicate code significantly, there are many of them and they reside in different blueprints.

我知道有人问过类似的问题,但是没有人使用Flask回答.可以在不同的Web框架中进行操作,例如在Pyramid中使用谓词-可以在此答案中找到示例代码.

I am aware that similar question has been asked, but nobody answered it using Flask. It's possible to do it in different web frameworks, for example in Pyramid using predicates - sample code can be found in this answer.

推荐答案

我写了装饰器这样做(在此处复制以供后代使用).这只是一个粗略的想法,可以进一步改进(例如,当没有匹配给定MIME类型的处理程序时,返回406 Not Acceptable响应,而不是使用默认处理程序).评论中有更多解释.

I wrote a decorator which does that (copying here for posterity). It's just a rough idea that could be improved further (e.g. returning 406 Not Acceptable response instead of using the default handler when there are no handlers that match given MIME type). More explanations are in the comments.

import functools
from flask import Flask, request, jsonify

app = Flask(__name__)

def accept(func_or_mimetype=None):
    """Decorator which allows to use multiple MIME type handlers for a single
    endpoint.
    """

    # Default MIME type.
    mimetype = 'text/html'

    class Accept(object):
        def __init__(self, func):
            self.default_mimetype = mimetype
            self.accept_handlers = {mimetype: func}
            functools.update_wrapper(self, func)

        def __call__(self, *args, **kwargs):
            default = self.default_mimetype
            mimetypes = request.accept_mimetypes
            best = mimetypes.best_match(self.accept_handlers.keys(), default)
            # In case of Accept: */*, choose default handler.
            if best != default and mimetypes[best] == mimetypes[default]:
                best = default
            return self.accept_handlers[best](*args, **kwargs)

        def accept(self, mimetype):
            """Register a MIME type handler."""

            def decorator(func):
                self.accept_handlers[mimetype] = func
                return func
            return decorator

    # If decorator is called without argument list, return Accept instance.
    if callable(func_or_mimetype):
        return Accept(func_or_mimetype)

    # Otherwise set new MIME type (if provided) and let Accept act as a
    # decorator.
    if func_or_mimetype is not None:
        mimetype = func_or_mimetype
    return Accept

@app.route('/')
@accept     # Or: @accept('text/html')
def index():
    return '<strong>foobar</strong>'

@index.accept('application/json')
def index_json():
    return jsonify(foobar=True)

@index.accept('text/plain')
def index_text():
    return 'foobar\n', 200, {'Content-Type': 'text/plain'}

这篇关于根据Flask中的Accept报头路由请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆