基于 Flask 中的 Accept header 路由请求
Route requests based on the Accept header in Flask
我想根据接受 HTTP header 路由到不同的 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")
我没有在Werkzeug Rule constructor中找到相关的选项,这是Flask使用的。它是缺少的功能还是有可能以不同的方式实现相同的效果,例如通过在路由之前拦截和修改 URL 路径?
我不想将视图合并为一个视图,因为这会使代码显着复杂化,它们有很多,而且它们位于不同的蓝图中。
我知道 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。
我写了一个 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'}
我知道这是一个老问题,但我最终在这里寻找类似的东西,所以我希望它能帮助其他人。
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'
When one tries to access the endpoint without a valid Accept header:
$ curl localhost:5000 -I
HTTP 415 (Unsupported Media Type)
您可以 return 基于接受 header 使用 request 的不同响应类型。例子.
if request.accept_mimetypes['application/json']:
return jsonify(<object>), '200 OK'
我想根据接受 HTTP header 路由到不同的 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")
我没有在Werkzeug Rule constructor中找到相关的选项,这是Flask使用的。它是缺少的功能还是有可能以不同的方式实现相同的效果,例如通过在路由之前拦截和修改 URL 路径?
我不想将视图合并为一个视图,因为这会使代码显着复杂化,它们有很多,而且它们位于不同的蓝图中。
我知道 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。
我写了一个 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'}
我知道这是一个老问题,但我最终在这里寻找类似的东西,所以我希望它能帮助其他人。
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'
When one tries to access the endpoint without a valid Accept header:
$ curl localhost:5000 -I
HTTP 415 (Unsupported Media Type)
您可以 return 基于接受 header 使用 request 的不同响应类型。例子.
if request.accept_mimetypes['application/json']:
return jsonify(<object>), '200 OK'