Направляйте запросы на основе заголовка Accept в веб-фреймворках Python
У меня есть некоторый опыт работы с различными веб-фреймворками (Django, web.py, Pyramid и CherryPy), и мне интересно, в какой из них будет проще и, надеюсь, чище реализовать диспетчер маршрутов для другого "представления / обработчика" на основе заголовок "Принять" и метод HTTP, например:
Accept: application/json
POST /post/
обрабатывается иначе, чем:
Accept: text/html
POST /post/
Таким образом, запрос направляется в конкретное представление соответствующего обработчика MIME "application/json" и HTTP-метода "POST".
Я знаю, как реализовать нечто подобное в CherryPy, но я теряю использование инструментов CherryPy для внутреннего перенаправления запроса, потому что я вызываю определенный метод напрямую, а не автоматически из диспетчера. Другой вариант - реализовать новый диспетчер с нуля, но это последний вариант.
Я знаю об альтернативе использования расширений в URL, как /post.json
или же /post/.json
, но я хочу сохранить тот же URL?
3 ответа
Если все, что вам нужно, это одна структура, которая может сделать это легко, тогда используйте pyramid
,
Определения представления Pyramid создаются с использованием предикатов, а не только маршрутов, и представление соответствует, только если все предикаты совпадают. Одним из таких предикатов является accept
предикат, который делает именно то, что вы хотите; сделать переключение вида в зависимости от Accept
заголовок легко и просто:
from pyramid.view import view_config
@view_config(route_name='some_api_name', request_method='POST', accept='application/json')
def handle_someapi_json(request):
# return JSON
@view_config(route_name='some_api_name', request_method='POST', accept='text/html')
def handle_someapi_html(request):
# return HTML
Мне нужно было сделать это в Django, и поэтому я написал часть промежуточного программного обеспечения, чтобы сделать это возможным: http://baltaks.com/2013/01/route-requests-based-on-the-http-accept-header-in-django
Вот код:
# A simple middleware component that lets you use a single Django
# instance to serve multiple versions of your app, chosen by the client
# using the HTTP Accept header.
# In your settings.py, map a value you're looking for in the Accept header
# to a urls.py file.
# HTTP_HEADER_ROUTING_MIDDLEWARE_URLCONF_MAP = {
# u'application/vnd.api-name.v1': 'app.urls_v1'
# }
from django.conf import settings
class HTTPHeaderRoutingMiddleware:
def process_request(self, request):
try:
for content_type in settings.HTTP_HEADER_ROUTING_MIDDLEWARE_URLCONF_MAP:
if (request.META['HTTP_ACCEPT'].find(content_type) != -1):
request.urlconf = settings.HTTP_HEADER_ROUTING_MIDDLEWARE_URLCONF_MAP[content_type]
except KeyError:
pass # use default urlconf (settings.ROOT_URLCONF)
def process_response(self, request, response):
return response
Я не совсем уверен, что вы подразумеваете под "внутренним перенаправлением", но если вы посмотрите на код, вы увидите, что tools.accept - действительно тонкая оболочка для lib.cptools.accept, которую вы можете легко вызвать из своего собственного кода., Передайте ему список типов контента, которые ваш сервер может отправить, и он скажет вам, какой клиент предпочитает, или выдаст 406, если типы, которые вы отправляете, и типы, которые принимает клиент, не пересекаются.