内容协商-Django REST框架
内容协商
http有关于“内容协商”的几种机制的规定--当有多个表示时,为给定的响应选择最佳表示的过程。
— RFC 2616、Fielding等人著。
内容协商是根据客户端或服务器首选项选择多个可能的表示形式中的一个返回到客户端的过程。
确定接受的呈现器
REST框架使用一种简单的内容协商风格,根据可用呈现器、每个呈现器的优先级和客户端的Accept:
头球。所使用的样式部分是客户端驱动的,部分是服务器驱动的。
- 更具体的媒体类型优先于较不特定的媒体类型。
- 如果多个媒体类型具有相同的特殊性,则根据为给定视图配置的呈现器的顺序给予优先考虑。
例如,给定以下内容Accept
标题:
application/json; indent=4, application/json, application/yaml, text/html, */*
每种特定媒体类型的优先事项是:
application/json; indent=4
-
application/json
,application/yaml
和text/html
*/*
如果只将请求的视图配置为YAML
和HTML
,则REST框架将选择在renderer_classes
清单或DEFAULT_RENDERER_CLASSES
背景。
的更多信息。HTTP Accept
标题,见RFC 2616
注在确定偏好时,REST框架不考虑“Q”值。使用“Q”值会对缓存产生负面影响,作者认为它们是一种不必要的、过于复杂的内容协商方法。
这是一种有效的方法,因为HTTP规范故意低估了服务器应该如何权衡基于服务器的首选项和基于客户端的首选项。
自定义内容协商
您不太可能为REST框架提供自定义内容协商方案,但如果需要,您可以这样做。若要实现自定义内容协商方案,请重写BaseContentNegotiation
.
REST框架的内容协商类处理请求的适当解析器和响应的适当呈现器的选择,因此您应该实现.select_parser(request, parsers)
和.select_renderer(request, renderers, format_suffix)
方法。
这个select_parser()
方法应从可用解析器列表中返回一个解析器实例,或None
如果没有一个解析器能够处理传入的请求。
这个select_renderer()
方法应返回(呈现器实例,媒体类型)的两个元组,或引发NotAcceptable
例外。
例
下面是一个自定义内容协商类,它在选择适当的解析器或呈现器时会忽略客户端请求。
from rest_framework.negotiation import BaseContentNegotiation
class IgnoreClientContentNegotiation(BaseContentNegotiation):
def select_parser(self, request, parsers):
"""
Select the first parser in the `.parser_classes` list.
"""
return parsers[0]
def select_renderer(self, request, renderers, format_suffix):
"""
Select the first renderer in the `.renderer_classes` list.
"""
return (renderers[0], renderers[0].media_type)
设置内容协商
默认内容协商类可以全局设置,使用DEFAULT_CONTENT_NEGOTIATION_CLASS
背景。例如,下面的设置将使用我们的示例IgnoreClientContentNegotiation
班级,等级。
REST_FRAMEWORK = {
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'myapp.negotiation.IgnoreClientContentNegotiation',
}
还可以使用APIView
基于类的视图。
from myapp.negotiation import IgnoreClientContentNegotiation
from rest_framework.response import Response
from rest_framework.views import APIView
class NoNegotiationView(APIView):
"""
An example view that does not perform content negotiation.
"""
content_negotiation_class = IgnoreClientContentNegotiation
def get(self, request, format=None):
return Response({
'accepted media type': request.accepted_renderer.media_type
})
网友评论