cookie与session、django中间件及中间件的五个方法
cookie与session简介
HTTP协议四大特性
- 基于请求响应
- 基于TCP/IP应用于应用层之上的协议
- 无状态
- 无连接
基于http的特性,服务端无法识别客户端的状态,互联网刚刚兴起的时候,所有人访问网址都是一样的数据,服务端无法访问客户端。
随着互联网的发展,考虑到用户的安全性以及用户的唯一标识,服务端不得不想办法记住客户端的状态。cookie与session应运而生。
cookie与session
- 保存在客户端跟用户信息(状态)相关的数据
- 保存在服务端上跟用户信息(状态)相关的数据
session的工作需要依赖于cookie,就算是目前所有能够识别用户身份的网址也都需要使用cookie,浏览器也可以设置禁用cookie。
cookie
什么是Cookie
cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时,浏览器会自动携带这些键值对,以便服务器提取有用信息
Cookie的工作原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用的信息。
查看Cookie
使用Chrome浏览器,打开开发者工具
django操作cookie
如果想要让客户端浏览器保存cookie需要HttpResponse对象调用方法
基于视图函数必须返回HttpResponse对象,我们在编写视图函数的时候,往往都是按如下的方式:
return HttpResponse()
return JsonResponse()
return render()
return redirect()
但是如果要操作cookie的话就需要变形了,因为我们要用HttpResponse对象来操作cookie的一系列方法。
obj=HttpResponse('xxx')
obj.操作cookie的方法
return obj
因为JsonResponse、render、redirect都是直接或间接的属于HttpResponse对象,所以使用方法也是一致。
登录设置cookie
def login(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
if username=='jason' and password=='123':
obj =HttpResponse('登录成功')
obj.set_cookie('name','jason',max_age=1000)
return obj
return render(request,'login.html')
装饰器装饰视图函数
cookie校验是否登录装饰器
在使用装饰器之前我们需要知道如何获取请求路径的三个方法
def home(request):
print(request.path)
print(request.path_info)
print(request.get_full_path())
return HttpResponse("主页面")
在浏览器中输入home视图函数所对应的路由,并携带一些get请求的数据
登录认证装饰器:在未登录状态下在url后添加get请求数据即添加登录成功跳转的路径地址,登录成功后就可以通过GET请求携带的该路径实现跳转。
def login_auth(func_name):
def is_login(request,*args,**kwargs):
if request.COOKIES.get('name'):
res=func_name(request,*args,**kwargs)
return res
else:
target_path=request.path_info
return redirect(f'/login/?path={target_path}')
给多个视图函数装上装饰器并判断是否登录,登记后返回指定路径,如果未指定路径就返回主页面
'装饰器'
def login_auth(func_name):
def is_login(request,*args,**kwargs):
if request.COOKIES.get('name'):
res=func_name(request,*args,**kwargs)
return res
else:
target_path=request.path
return redirect(f'/login/?path={target_path}')
return is_login
def login(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
if username=='jason' and password=='123':
target_path=request.GET.get('path')
if target_path:
obj=redirect(f'{target_path}')
else:
return redirect('/home/')
obj=HttpResponse('登录成功')
obj.set_cookie('name','jason')
return obj
return render(request,'login.html')
'主页面'
@login_auth
def home(request):
return HttpResponse("主页面")
'其他页面'
@login_auth
def index(request):
return HttpResponse('其他页面')
session
session的由来
cookie虽然在一定程度上解决了保持状态的需求,但是由于cookie本身最大支持4096字节,以及cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一个新的东西,它能支持更多的字节,并且它保存在服务器,有较高的安全性。这就是session。
基于http协议的无状态特征,服务器根本就不知道访问者是谁。那么上述的cookie就起到桥接的作用。
我们可以给每个客户端的cookie分配一个唯一的id,这样用户在访问时,通过cookie,服务器就知道来的人是谁。然后我们再根据不同的cookie的id,在服务器上保证一段时间的私密资料,如账号密码等待。
总结而言:cookie弥补了http无状态的不足,让服务器知道来的人是谁,但是cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过cookie识别不同的用户,对应的在session里保存私密的信息以及超过4096字节的文本。
上述所说的cookie和session其实是共通性的东西,不限于语言和框架。
django操作session
操作session流程
- 首先需要执行数据库迁移同步命令,django会自动创建一张
django_session
的表,用来保存session键值对
- 创建路由,对应路由的视图函数
# url
path('setSession/',views.set_session)
# views.py
def set_session(request):
request.session['name']='jason'
return HttpResponse('我是session')
- 在浏览器端访问该路径
- 查看django_session表数据
由此我们可以看出,当用户访问服务端,服务端会创建一个加密的session键值对({'name':'jason'),并将sessionid(session_key)返回给浏览器,存储在Cookie中。
- 服务端取session的值
def get_session(request):
res=request.session.get('name')
print(res)
return HttpResponse('拿到session')
服务端会自动从请求的Cookie中携带的sessionid对应的随机字符串去django_session中匹配数据,并将该数据解密并展示。
session的存储位置可以有五种模式
- 数据库
- 缓存数据库
- 文件
- 缓存+数据库
- 加密
django中session相关方法
# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 会话session的key
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
# 删除当前会话的所有Session数据===>只删浏览器的sessionid
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。===>服务端的session数据和客户端的sessionid全部删除
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
django中间件
什么是中间件
中间件就是一个用来处理django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变django的输入和输出。每个中间件组件都负责做一些特定的功能。
但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。
说的直白一点中间件就是帮助我们在视图函数执行之前和执行之后度可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,django框架会在请求的特定时间去执行这些方法。
django中自带了七个中间件,我们也可以基于此做一些扩展
自定义中间件方法
django自定义中间件中可以有五个方法
process_request
process_response
process_view
process_template_response
process_exception
自定义中间件流程
在app01下创建一个文件夹并在该文件夹内新建py文件,写一个类继承MiddlewareMixin
类,并将该类的路径注册到settings.py
的MIDDLEWARE
中。
process_request方法
# 自定义中间件类
from django.utils.deprecation import MiddlewareMixin
class MyMid1(MiddlewareMixin):
def process_request(self,request):
print('my mid1')
class MyMid2(MiddlewareMixin):
def process_request(self,request):
print('my mid2')
# settings中注册中间件路径
MIDDLEWARE = [
'app01.utils.mymid.MyMid1',
'app01.utils.mymid.MyMid2'
]
- 当请求来的时候会按照配置文件中注册了的中间件,从上往下依次执行每一个中间件里面的process_request方法,如果没有直接跳过
- 该方法如果返回了HttpResponse对象,那么请求不会再往后执行,原路返回
注意:如果请求的过程中process_request方法直接返回了HttpResponse对象,那么会原地执行同级别process_response方法返回(flask则不同)
process_response方法
# 自定义中间件类
class MyMid1(MiddlewareMixin):
def process_response(self,request,response):
print('my mid1')
return response
class MyMid2(MiddlewareMixin):
def process_response(self, request, response):
print('my mid2')
return response
# settings中注册中间件路径
MIDDLEWARE = [
'app01.utils.mymid.MyMid1',
'app01.utils.mymid.MyMid2'
]
- 响应走的时候会按照配置文件中注册了的中间件,从下往上依次执行每一个中间件里面的
process_response
方法,没有则直接跳过。 - 该方法有两个形参request和response,并且默认情况下应该返回response
- 该方法也可以自己返回HttpResponse对象,相当于狸猫换太子。一旦返回HttpResponse对象对象,后续的中间件都将该对象返回
process_view方法
class MyMid1(MiddlewareMixin):
def process_view(self,request,view_func,view_args,view_kwargs):
print('from my mid1')
print(view_func)
class MyMid2(MiddlewareMixin):
def process_view(self,request,view_func,view_args,view_kwargs):
print('from my mid2')
print(view_func)
在路由匹配成功之后,执行视图函数之前,自动触发
process_exception方法
class MyMid1(MiddlewareMixin):
def process_exception(self,request, exception):
print(exception)
print('MyMdd1 process_exception')
当视图函数报错之后,自动触发
process_temlate_response方法
# 自定义中间件类
class MyMid1(MiddlewareMixin):
def process_template_response(self,request,response):
print('from process_template_response')
return response
# 视图函数
def my_mid(request):
def render():
print('from my_mid in render')
return HttpResponse('inner render')
obj=HttpResponse('ok')
obj.render=render
return obj
当视图函数返回的数据对象中含有render属性对应render函数才会触发。