我想基于Accept HTTP标头路由到不同的Flask视图,例如:
@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")
我没有找到Flask使用的Werkzeug Rule constructor中的相关选项。它是一个缺失的功能还是可以以不同的方式实现相同的效果,例如通过在路由之前拦截和修改URL路径?
我不想将视图合并为一个,因为它会使代码复杂化,其中有很多并且它们位于不同的蓝图中。
我知道已经问过similar question,但是没有人使用Flask回答它。可以在不同的Web框架中进行,例如在Pyramid中使用predicates - 示例代码可以在this answer中找到。
答案 0 :(得分:4)
我写了decorator这样做(在这里复制后代)。它只是一个可以进一步改进的粗略想法(例如,当没有匹配给定MIME类型的处理程序时,返回406 Not Acceptable
响应而不是使用默认处理程序)。评论中有更多解释。
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'}
答案 1 :(得分:4)
我知道这是一个老问题,但我最终在这里寻找类似的东西,所以我希望它可以帮助其他人。
flask_accept具有通过不同路由处理不同Accept类型的功能。
from flask import Flask, jsonify
from flask_accept import accept
app = Flask(__name__)
@app.route('/')
@accept('text/html')
def hello_world():
return 'Hello World!'
@hello_world.support('application/json')
def hello_world_json():
return jsonify(result="Hello World!")
if __name__ == '__main__':
app.run()
如果您只想拒绝请求,具体取决于它们是否是特定数据类型,您还可以使用Flask-Negotiate
from flask import Flask
from flask_negotiate import consumes, produces
app = Flask(__name__)
@app.route('/consumes_json_only')
@consumes('application/json')
def consumes_json_only():
return 'consumes json only'
当尝试访问没有有效Accept标头的端点时:
$ curl localhost:5000 -I
HTTP 415 (Unsupported Media Type)
答案 2 :(得分:0)
您可以使用request根据Accept标头返回不同的响应类型。例子。
if request.accept_mimetypes['application/json']:
return jsonify(<object>), '200 OK'