RESTFUL介绍
- 本质就是一个规范,翻译为"表现层状态转化","表现层"其实指的是"资源"(Resources)的"表现层"。
- REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的信息实体,可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。
RESTFUL设计规范
- 推荐使用cbv
- API与用户的通信协议,建议总是使用HTTPs协议。
- 域名
- https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
- https://example.org/api/ API很简单
- 版本
URL,如:https://api.example.com/v1/ - 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
https://api.example.com/v1/zoos https://api.example.com/v1/animals
https://api.example.com/v1/employees - method
- GET :从服务器取出资源(一项或多项)
- POST :在服务器新建一个资源
- PUT :在服务器更新资源(客户端提供改变后的完整资源)
- PATCH :在服务器更新资源(客户端提供改变的属性)
- DELETE :从服务器删除资源
- 过滤,通过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
- 返回结果
- GET /collection:返回资源对象的列表(数组)
- GET /collection/resource:返回单个资源对象
- POST /collection:返回新生成的资源对象
- PUT /collection/resource:返回完整的资源对象
- PATCH /collection/resource:返回完整的资源对象
- DELETE /collection/resource:返回一个空文档
- 状态码
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
源码流程及基础认证示例
源码流程(以一个示例说明,如下,views下的api_view类)
from django.views import View
from rest_framework.views import APIView #通过查看源码发现,APIView 继承了django.views 下的View
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
十三、#自定义一个认证实例
class MyAuthentication(object):
def authenticate(self,request):
#做用户认证,例如可以去数据库获取用户名和密码进行校验,这里只做简单示例
token = request._request.GET.get('token') #这里获取原生的request里面的值
if not token:
raise exceptions.AuthenticationFailed("用户认证失败")
return ('xxx',None)
def authenticate_header(self,*args):
pass
class v1_View(APIView): #① 自定义的函数执行类
authentication_classes = [MyAuthentication,] #引用上面的认证实例,这里对应下面的第⑦步骤
def get(self,request,*args,**kwargs):
#self.dispatch() #② 默认后台执行
ret = {
'code':1000,
'msg':'success'
}
return HttpResponse(json.dumps(ret),status=201)
def post(self, request, *args, **kwargs):
return HttpResponse("POST")
def put(self, request, *args, **kwargs):
return HttpResponse("PUT")
def delete(self, request, *args, **kwargs):
return HttpResponse("DELETE")
dispatch源码
def dispatch(self, request, *args, **kwargs):
#③、
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs) #④、
self.request = request #这里的request为第④步处理后的request
self.headers = self.default_response_headers # deprecate?
⑨、#执行函数
try:
self.initial(request, *args, **kwargs) #⑩
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs) #这里的request为上面经过self.initialize_request实例化的request,并将这个request传递给views里定义的各个方法
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
步骤④后续,initialize_request函数源码
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
⑤、
return Request(
request, #这里为传入的原生的request
parsers=self.get_parsers(),
authenticators=self.get_authenticators(), ⑥、
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
查看第④步骤下Request的源码(这里包含众多request里要获取的值)
class Request(object):
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request #这里为原生的request,通过self_request获取
self.parsers = parsers or ()
self.authenticators = authenticators or () #获取认证类的实例化对象
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty
if self.parser_context is None:
self.parser_context = {}
self.parser_context['request'] = self
self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
force_user = getattr(request, '_force_auth_user', None)
force_token = getattr(request, '_force_auth_token', None)
if (force_user is not None or force_token is not None):
forced_auth = ForcedAuthentication(force_user, force_token)
self.authenticators = (forced_auth,)
................
................
................
步骤⑥后续 get_authenticators函数
def get_authenticators(self):
return [auth() for auth in self.authentication_classes] #⑦、
步骤⑦后续
class APIView(View):
# The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #⑧、
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
metadata_class = api_settings.DEFAULT_METADATA_CLASS
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
第⑩步骤后续
def initial(self, request, *args, **kwargs): #传入的request为经过第④步处理后的request
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
self.perform_authentication(request) #十一
self.check_permissions(request)
self.check_throttles(request)
self.perform_authentication源码
def perform_authentication(self, request):
#执行 user函数
request.user
第十一步后续
Request方法,
@property
def user(self):
if not hasattr(self, '_user'):
self._authenticate() #十二 进行验证,查看源码
return self._user
十二后续
def _authenticate(self):
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self) #十三
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None: #如果登录了,返回一个元组
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated() #如果没有登录,就会报异常,这里也是调用没有验证的函数
说明
①、#默认情况下会继承django的View,但是引入了rest_framework下的APIView,查看源码发现,它同样继承django下的View,所以这里写APIView,除了会继承APIView还会继承View
②、根据cbv执行流程来看,请求经过url和view后,执行get或post等方法之前,会先执行self.dispatch()方法,查看dispatch源码,
③、#执行函数方法(get,post...)之前所做的操作
④、#这里self.initialize_request传入的request为原生的request,点击查看self.initialize_request源码
⑤、#对原生的request进行加工,传入Request函数,点击可查看源码
⑥、#这里调用get_authenticators(),首先会从views下自己定义的v1_view类里找有没有这个函数,如果没有定义,会去父类查找,点击查看get_authenticators()源码,([自己定义的认证类实例化()]),放到request,回到第④步,此时的request包含认证的实例对象和原生的request
⑦#这里返回一个列表,列表的内容为类的实例化的对象,如[foo(),bar()],这里的authentication_classes首先会从自己定义的v1_view里查找。如果没有就去父类找,先点击查看self.authentication_classes的源码,完后进行第⑧步后,然后放到Request函数,回到dispatch,进行第⑨步,此时的request封装了原生的request和authentication对象
⑧、#这里读取rest_framework的配置文件,如果自己定义了(v1_view类),则就会使用自己定义的类,否则返回到步骤⑦,
⑨、#执行函数
⑩、这里的request为第④步经过处理后的request,这里initial函数先从自定义的view里找,没有就去父类找,看initial源码
十一、经过处理后的request,这里返回执行request.user类,查看request.user类
十三 、#执行这个方法,验证用户是否登录,所以判定如果自定义认证时,需要加上这个方法
认证示例
views.py
from django.views import View
from rest_framework.views import APIView #通过查看源码发现,APIView 继承了django.views 下的View
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
#自定义一个认证实例
class MyAuthentication(object):
def authenticate(self,request):
token = request._request.GET.get('token')
if not token:
raise exceptions.AuthenticationFailed("用户认证失败")
return ('xxx',None)
def authenticate_header(self,*args):
pass
class v1_View(APIView):
authentication_classes = [MyAuthentication,] #引用上面的认证实例,通过源码流程原理可知道为什么引用
def get(self,request,*args,**kwargs):
self.dispatch()
ret = {
'code':1000,
'msg':'success'
}
return HttpResponse(json.dumps(ret),status=201)
def post(self, request, *args, **kwargs):
return HttpResponse("POST")
def put(self, request, *args, **kwargs):
return HttpResponse("PUT")
def delete(self, request, *args, **kwargs):
return HttpResponse("DELETE")