Day 58 cookie与session/django中间件
cookie
cookie产生的原因是因为HTTP协议是无状态的
无状态的意思就是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况
状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留.会话中产生的数据又是我们需要保存的,也就是说要保持状态.因此Cookie就是在这样一个场景下诞生的
什么是cookie
cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,一边服务器提取有用信息
cookie的原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是"谁"了
Django中操作Cookies
设置Cookie
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'tiny' and password == '123':
# 固定登陆成功后跳转的页面
old_path = request.GET.get('next')
if old_path:
obj = redirect(old_path)
else:
obj = render(request, 'home.html')
# 设置cookie值
obj.set_cookie('user_info', username)
return obj
return HttpResponse('密码错误')
获取cookie
def login_auth(func):
def inner(request, *args, **kwargs):
# 获取cookie
if request.COOKIES.get('user_info'):
res = func(request, *args, **kwargs)
return res
else:
target_path = request.path_info
return redirect('/login/?next=%s' % target_path)
return inner
删除cookie
def logout(request):
rep = redirect('/home/')
rep.delete_cookie('user_info')
return rep
session
Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
Django中操作Session
设置session
class MyLogin(View):
def get(self, request):
return render(request, 'login.html')
def post(self, request):
username = request.POST.get('name')
pwd = request.POST.get('pwd')
# print(pwd, type(pwd))
data = models.User.objects.filter(username=username)
user_obj = data[0]
if not user_obj:
return HttpResponse('当前用户不存在!')
if user_obj.pwd == pwd:
old_path = request.GET.get('next')
if old_path:
obj = redirect(old_path)
else:
obj = render(request, 'home.html')
# 设置session值
request.session['user_info'] = username
return obj
return render(request, 'login.html', {'msg': '密码错误'})
获取session
def login_auth(func):
def inner(request, *args, **kwargs):
# 获取session
if request.session.get('user_info'):
res = func(request, *args, **kwargs)
return res
else:
target_path = request.path_info
return redirect('/login/?next=%s' % target_path)
return inner
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数据
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。
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项目的Settings.py文件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
自定义中间件
中间件可以定义五个方法,分别是:
需要掌握:
- process_request(self, request)
- process_response(request)
需要了解
- process_view(self, request, view_func, view_args, view_kwargs)
- process_exception(self, request, exception)
- process_template_response(self, request, response)
以上方法的返回值可以是None或者一个HttpResponse对象,如果是None,则继续按照Django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回用户
process_request
总结:
- 中间件的process_request方法是在执行视图函数之前执行的
- 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的
- 不同中间件之间传递的request都是同一个对象
process_response
总结:
- 多个中间中的process_response方法是安装MIDDLEWARE的注册顺序倒序执行的
- 该方法必须有两个参数,并且必须返回response形参,不返回直接报错
- 该方法返回什么HttpResponse对象,前端就能获得什么
process_view
- 路由匹配成功之后执行视图函数之前触发
- 如果该方法返回了HttpResponse对象,那么会从下往上经过每一个中间件里面的process_response方法
process_template_response
当你返回对象中含有render属性指向的是一个render方法的时候才会触发,从上往下的顺序
def mdzz(request):
print('我是视图函数mdzz')
def render():
return HttpResponse('你好呀 我是奇葩')
obj = HttpResponse('我很好 好的像个傻逼一样')
obj.render = render
return obj
process_exception
当视图函数中出现错误时,会自动触发,顺序是从上往下