Route requests based on the Accept header in Python web frameworks

感情迁移 提交于 2019-12-22 11:29:40

问题


I have some experience with different web frameworks (Django, web.py, Pyramid and CherryPy), and I'm wondering in which one will it be easier and hopefully cleaner to implement a route dispatcher to a different "view/handler" based on the "Accept" header and the HTTP method e.g.:

Accept: application/json
POST /post/

is handled different than:

Accept: text/html
POST /post/

So the request gets routed to the particular view of the corresponding handler of the MIME "application/json" and the HTTP method "POST".

I do know how to implement something like that in CherryPy, but I lose the use of the CherryPy tools for the internal redirection of the request because I'm calling the specific method directly instead of automagically from the dispatcher. Another option is to implement a full new dispatcher from scratch, but that's the last option.

I'm aware of the alternative to use extensions in the url like /post.json or /post/.json, but I'm looking to keep the same url?


回答1:


If all you are looking for is one framework that can do this easily, then use pyramid.

Pyramid view definitions are made with predicates, not just routes, and a view only matches if all predicates match. One such predicate is the accept predicate, which does exactly what you want; make view switching depending on the Accept header easy and simple:

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



回答2:


I needed to do this in Django, and so I wrote a piece of middleware to make it possible: http://baltaks.com/2013/01/route-requests-based-on-the-http-accept-header-in-django

Here is the code:

# 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



回答3:


I'm not suite sure what you mean by "internal redirection", but if you look at the code you can see that tools.accept is a really thin wrapper around lib.cptools.accept, which you can call from your own code easily. Hand it a list of Content-Types your server can send, and it will tell you which one the client prefers, or raise 406 if the types you emit and the types the client accepts don't overlap.



来源:https://stackoverflow.com/questions/13998607/route-requests-based-on-the-accept-header-in-python-web-frameworks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!