赞
踩
1、只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.views import exception_handler
查看源码:如下
模块: import rest_framework.settings
模块: from rest_framework.views import APIView
import rest_framework.settings # 从settings中找源码
源码84行左右
# Exception handling
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
'NON_FIELD_ERRORS_KEY': 'non_field_errors',
2、drf只要出了异常,就会执行:‘EXCEPTION_HANDLER’: ‘rest_framework.views.exception_handler’ 这个函数
执行这个’EXCEPTION_HANDLER’: ‘rest_framework.views.exception_handler’
就会执行 rest_framework.views.exception_handler
''' 去继承的APIView中的dispatch方法中的 except Exception as exc: response = self.handle_exception(exc) 异常代码执行handle_exception方法 def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.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) # 走这一行执行self.handle_exception(exc)代码然后执行handle_exception方法 except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response '''
''' 执行handle_exception 方法 时就会执行方法中exception_handler = self.get_exception_handler() 这一行代码 但是这一行代码就是 前面 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler’中的rest_framework.views.exception_handle函数 def handle_exception(self, exc): """ Handle any exception that occurs, by returning an appropriate response, or re-raising the error. """ if isinstance(exc, (exceptions.NotAuthenticated, exceptions.AuthenticationFailed)): # WWW-Authenticate header for 401 responses, else coerce to 403 auth_header = self.get_authenticate_header(self.request) if auth_header: exc.auth_header = auth_header else: exc.status_code = status.HTTP_403_FORBIDDEN # 最终执行这一行代码 exception_handler = self.get_exception_handler() context = self.get_exception_handler_context() response = exception_handler(exc, context) if response is None: self.raise_uncaught_exception(exc) response.exception = True return response '''
3、drf只要出了异常,就会执行:‘EXCEPTION_HANDLER’: ‘rest_framework.views.exception_handler’ 这个函数
看这个函数 rest_framework.views.exception_handler
4、导入这个执行异常函数的模块
from rest_framework.views import exception_handler
点进去里面就是def exception_handler(exc, context):函数
下面是源代码
''' def exception_handler(exc, context): """ Returns the response that should be used for any given exception. By default we handle the REST framework `APIException`, and also Django's built-in `Http404` and `PermissionDenied` exceptions. Any unhandled exceptions may return `None`, which will cause a 500 error to be raised. """ if isinstance(exc, Http404): exc = exceptions.NotFound() elif isinstance(exc, PermissionDenied): exc = exceptions.PermissionDenied() if isinstance(exc, exceptions.APIException): headers = {} if getattr(exc, 'auth_header', None): headers['WWW-Authenticate'] = exc.auth_header if getattr(exc, 'wait', None): headers['Retry-After'] = '%d' % exc.wait if isinstance(exc.detail, (list, dict)): data = exc.detail else: data = {'detail': exc.detail} set_rollback() return Response(data, status=exc.status_code, headers=headers) return None '''
场景:只要drf出现异常就会执行上面exception_handler函数
设置drf的异常查看是否执行exception_handler函数
设置源代码(验证完成要改回来)
要执行的drf代码
# 场景只要drf出现异常就会执行上面exception_handler函数 # 设置drf的异常查看是否执行exception_handler函数 from rest_framework.exceptions import APIException from app01 import models class BookView(APIView): def get(self, request): # 1、接受前端的信息 name = request.query_params.get('name') pwe = request.query_params.get('pwd') # 在这里设置异常验证是否drf报错是否执行了源代码中的exception_handler函数 # 这里了源代码中的exception_handler函数 设置了输出函数, # 只要执行exception_handler函数,打印输出‘我不信’ raise APIException('我出错误了') # 2、查询数据库信息 book_obj = models.Book.objects.all() # 查询所有数据 if name: book_obj = book_obj.order_by(name) else: book_obj = book_obj.filter(name__contains=name)
用postman模拟前端发送数据
后端执行代码结果:
到这里就验证了上面的问题
drf出现异常就会执行exception_handler函数
到这里就有一个问题,把源码改了之后自己的drf代码可以执行,但是把drf代码给别人就实现不了功能,所以我们可以自定义一个函数,配置一下,以后出了异常,执行我们自己的函数,我们称这个函数为:自定义异常
1、创建一个文件(exceptions.py)用来写自定义异常的函数
# 设置 ''' def exception_handler(exc, context): if isinstance(exc, Http404): exc = exceptions.NotFound() elif isinstance(exc, PermissionDenied): exc = exceptions.PermissionDenied() # 这里就是判断exc是不是APIException的对象,如果是就返回下面return Response(data, status=exc.status_code, headers=headers) # 如果不是就返回 return None if isinstance(exc, exceptions.APIException): headers = {} if getattr(exc, 'auth_header', None): headers['WWW-Authenticate'] = exc.auth_header if getattr(exc, 'wait', None): headers['Retry-After'] = '%d' % exc.wait # 这里是处理异常详细数据有多种形式 if isinstance(exc.detail, (list, dict)): data = exc.detail else: data = {'detail': exc.detail} set_rollback() return Response(data, status=exc.status_code, headers=headers) return None ''' # 如果异常对象是drf的APIException对象,就会返回Response # exception_handler只处理了drf的异常,其它的异常需要我们自己处理 # 如果异常对象不是drf的APIException对象,就会返回None # isinstance() 判断一个对象是不是某个类的对象,返回bool值 isinstance(对象,类) # issubclass() 判断一个类,是不是另一个类的子类,返回bool值 from rest_framework.response import Response from rest_framework.views import exception_handler def common_exception_handler(exc, context): # 只要走到这里,一定出异常了,我们正常的项目要记录日志(后面讲) # 这里调用exception_handler函数方法 # 这个方法有两种可能:一个是Response对象,一个是None res = exception_handler(exc, context) # 这里的if res 表示:如果有值,代表的是drf的APIException对象的错误 # if判断下面处理APIException对象的错误信息 # 如果没有值,代表的是,其他异常 # 这里统一返回错误信息格式 return Response({'code': 505, 'msg': '有问题了', 'data': 'jdksajdk'}) if res: # 只要代码执行到这里,就说明是drf异常,它APIException处理了 # 获取错误的信息 if isinstance(res.data, dict): detail = res.data.get('detail') else: detail = res.data # 这里返回的信息是定制给前端的错误信息 return Response({'code': 505, 'msg': detail}) else: # 说明是其它异常,它是APIException没有处理的异常 # 这里返回的信息是定制给前端的错误信息 # return Response({'code': 4556, 'msg': "系统异常,请联系系统管理员"}) return Response({'code': 4556, 'msg': str(exc)})
2、写视图类代码
from app01 import models from rest_framework.views import APIView class BookView(APIView): def get(self, request): # 1、接受前端的信息 name = request.query_params.get('name') pwe = request.query_params.get('pwd') # 在这里设置异常验证是否drf报错是否执行了源代码中的exception_handler函数 # 这里源代码中的exception_handler函数 设置了输出函数, # 只要执行exception_handler函数,打印输出‘我不信’ # raise APIException('我出错误了') # 设置drf异常,前端能看到这个中文 raise Exception('django中的异常数据') # 设置django异常 # # 其他错误 # l = [1, 2, 3] # print(l[9]) # 2、查询数据库信息 book_obj = models.Book.objects.all() # 查询所有数据 if name: book_obj = book_obj.order_by(name) else: book_obj = book_obj.filter(name__contains=name)
3、路由
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 开始设置异常的路由
path('books/', views.BookView.as_view()),
]
4、配置文件配置
# 自定义异常配置文件中要加入
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler',
}
5、展示
drf异常数据返回
django异常错误
其他异常错误
# 对于前端来讲,后端即便报错,也要返回统一的格式,前端便于处理
{code:999,msg:'系统异常,请联系系统管理员'}
# 只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.views import exception_handler
### 注意:exception_handler
# 如果异常对象是drf的APIException对象,就会返回Response
# exception_handler只处理了drf的异常,其它的异常需要我们自己处理
# 如果异常对象不是drf的APIException对象,就会返回None
# 补充:
# isinstance() 判断一个对象是不是某个类的对象 isinstance(对象,类)
# issubclass() 判断一个类,是不是另一个类的子类
# 后端把接口写好后 -登录接口 -注册接口 -查询所有图书带过滤接口 # 前端人员需要根据接口文档,进行前端开发 # 前后端需要做对接----》对接第一个东西就是这个接口文档---》前端照着接口文档开发 # 公司3个人,每个人开发了10个接口,3个人都要同时写接口文档 # 接口文档的编写形式 -1 world,md,编写,大家都可以操作,写完放在git,公司的文档管理平台上 -2 第三方的接口文档平台(收费) https://www.showdoc.com.cn/ -3 公司自己开发接口文档平台 -4 公司使用开源的接口文档平台,搭建 -YAPI:百度开源的 -https://zhuanlan.zhihu.com/p/366025001 -5 项目自动生成接口文档 -coreapi -swagger # 使用coreapi自动生成接口文档 -使用步骤: -1 安装:pip3 install coreapi -2 加一个路由 from rest_framework.documentation import include_docs_urls urlpatterns = [ path('docs/', include_docs_urls(title='站点页面标题')) ] -3 在视图类上加注释 -4 配置文件中配置: 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', -5 表模型或序列化类的字段上写 help_text--->会显示在接口文档的字段介绍上 -6 访问地址: http://127.0.0.1:8000/docs/
cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。
cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。
服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。
session是存储服务器端,cookie是存储在客户端,所以session的安全性比cookie高
获取session里的信息是通过存放在会话cookie里的session id获取的。而session是存放在服务器的内存中里,所以session里的数据不断增加会造成服务器的负担,所以会把很重要的信息存储在session中,而把一些次要东西存储在客户端的cookie里。
session的信息是通过sessionid获取的,而sessionid是存放在会话cookie中
当浏览器关闭的时候会话cookie消失,所以sessionid也就消失了,但是session的信息还存在服务器端,只是查不到所谓的session,但它并不是不存在
在Web领域基于Token的身份验证随处可见。在大多数使用Web API的互联网公司中,tokens 是多用户下处理认证的最佳方式。
以下几点特性会让你在程序中使用基于Token的身份验证
无状态、可扩展
支持移动设备
跨程序调用
安全
那些使用基于Token的身份验证的大佬们:大部分你见到过的API和Web应用都使用tokens。例如Facebook, Twitter, Google+, GitHub等。
CORS (跨域资源共享)
当我们扩展应用程序,让数据能够从不同设备上访问时,跨域资源的共享会是一个让人头疼的问题。在使用 Ajax 抓取另一个域的资源时(移动端访问我们的 API 服务器),可能会出现禁止请求的情况。
CSRF (跨站请求伪造)
用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。
在这些问题中,可扩展性是最突出的。因此我们有必要去寻求一种更有行之有效的方法。
基于Token的验证原理
基于 Token 的身份验证是无状态的,我们不用将用户信息存在服务器或 Session 中。这种概念解决了在服务端存储信息时的许多问题。没有 session 信息意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录和已经登录到了哪里。
实现思路:
1.用户登录校验,校验成功后就返回Token给客户端。
2.客户端收到数据后保存在客户端
3.客户端每次访问API是携带Token到服务器端。
4.服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码
当我们在程序中认证了信息并取得 token 之后,我们便能通过这个 token 做许多的事情。我们甚至能基于创建一个基于权限的token传给第三方应用程序,这些第三方程序能够获取到我们的数据(当然只限于该 token 被允许访问的数据)
# 总结
-会话管理
-cookie:客户端浏览器的键值对
-session:服务的的键值对(djangosession表,内存中,文件,缓存数据库)
-token:服务的生成的加密字符串,如果存在客户端浏览器上,就叫cookie
-三部分:头,荷载,签名
-签发:登录成功,签发
-认证:认证类中认证
# jwt:Json web token (JWT),web方向的token认证
-长得样子:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
# base64并不是一种加密反射,只是编码解码方式
# 字符串,可以转成base64编码格式:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 解码成base64
import json import base64 # d = {'user_id': 1, 'username': "lqz"} # # d_str = json.dumps(d) # print(d_str) # # 对字符串进行bashe64 编码 # res=base64.b64encode(bytes(d_str,encoding='utf-8')) # print(res) # eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImxxeiJ9 # 解码 # res=base64.b64decode('TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ=') # print(res) # 记住: base64 编码,长度一定是4的倍数。如果不够,用 = 补齐 # base64的用途 ''' 1 互联网中,前后端数据交互,使用base64编码 2 jwt 字符串使用base64编码 3 互联网中一些图片,使用base64编码 ''' s = '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' res = base64.b64decode(s) with open('code.png', 'wb') as f: f.write(res)
以上就是今天要讲的内容,本文仅仅简单介绍了的使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。