根据Flask中的Accept报头路由请求 [英] Route requests based on the Accept header in Flask
问题描述
我想基于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")
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屋!