今日学习内容
1.基于请求响应 2.基于TCP、IP作用于应用层之上协议 3.无状态 服务端无法识别客户端的状态 HTTP是一种不保存状态,即无状态(stateless)协议。 HTTP协议 自身不对请求和响应之间的通信状态进行保存。 互联网刚开始兴起的时候,所有人访问网址都是一样的数据,服务端无法识别客户端问题。 互联网发展后出现淘宝、京东、阿里,服务端不得不想办法记住客户端的状态。 cookie与session应运而生。 4.无连接
保存在客户端上跟用户信息(状态)相关的数据
保存在服务端上跟用户信息(状态)相关是数据 就是浏览器朝服务端发送请求,服务端保存用户信息,并以session方式返回给客户端里面存储一串随机字符串(令牌),保存在客服端上面。
session
的工作需要依赖于cookie
,就算目前所有能够识别用户身份
的网址也需要使用cookie
(客户端浏览器也有权拒绝保存cookie
)。
.
如果想要然客户端浏览器保存cookie需要HttpResonse对象调用的方法。
return HttpResponse() return render() return redirect() return JsonRespone()
设置cookie需要变形
obj = HttpResponse() obj.操作cookie的方法 return obj obj = render() obj.操作cookie的方法 return obj obj = redirect() obj.操作cookie的方法 return obj obj = JsonResponse() obj.操作cookie的方法 return obj
登录设置cookie
def set_cookie(request): obj = HttpResponse('中秋快乐') # 让浏览器保存cookie数据 obj.set_cookie('name', 'xz') return obj #login视图 def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'jason' and password == '123': obj.set_cookie('name', 'xz', max_age=3) return obj return render(request, 'login.html') #home视图 def home(request): if request.COOKIES.get('name'): return HttpResponse('home页面 只有登录的用户才可以查看') return redirect('/login/') #首页视图 def index(request): if request.COOKIES.get('name'): return HttpResponse('index页面 只有登录的用户才可以查看') return redirect('/login/')
问题:上述不管是有没有登录都是可以访问各个视图。
多个视图函数都需要校验用户是否登录:装饰器
print(request.path) 路由后缀 print(request.path_info) 路由后缀 print(request.get_full_path) 全路径
.
多个视图装上装饰器
@login_auth def home(request): return HttpResponse('home页面 只有登录的用户才可以查看') @login_auth def index(request): return HttpResponse('index页面 只有登录的用户才可以查看')
def set_cookie(request): obj = HttpResponse('中秋快乐') # 让浏览器保存cookie数据 obj.set_cookie('name', 'xz') return obj def login_auth(func_name): def inner(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/?next={target_path}') return inner def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'xz' and password == '123': target_path = request.GET.get('next') if target_path: obj = redirect(target_path) # 如果有值则跳转到指定页面 else: obj = redirect('/home/') # 如果没有值则跳转到首页 obj.set_cookie('name', 'xz', max_age=3) return obj return render(request, 'login.html') @login_auth def home(request): return HttpResponse('home页面 只有登录的用户才可以查看') @login_auth def index(request): return HttpResponse('index页面 只有登录的用户才可以查看')
如果记住用户登录之前想要访问的页面,用户登录成功之后自动跳转
场景1:用户访问了其他需要登录才可以访问的页面>>>:跳转到想要访问的。
场景2:用户直接访问的登录页面>>>:网址首页
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('next') if target_path: obj = redirect(target_path) # 如果有值则跳转到指定页面 else: obj = redirect('/home/') # 如果没有值则跳转到首页 obj.set_cookie('name', 'xz', max_age=3) return obj return render(request, 'login.html')
注意: 参数max_age
为cookie
保存信息时间长短。以秒
为单位。
1.首先用户访问某页面前是需要登录的,使用每个视图函数必须加个装饰器。 2.如果用户请求后cookie有该键值对对应的值,则执行该视图函数。 3.如果没有,则需要获取路由后缀或者全路径,返回并跳转到登录页面。 4.用户登录后,拿到next后面的路由后缀并跳转,没有则跳转到首页。 5.然后用户信息保存到cookie中。
获取Cookie: request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) --------------------------------------------------------------------------- 参数: default: 默认值 salt: 加密盐 max_age: 后台控制过期时间
.
设置Cookie: rep = HttpResponse(...) rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...) ----------------------------------------------------------------------------------- 参数: expires=None, 超时时间(IE requires expires, so set it if hasn't been already.) path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问 domain=None, Cookie生效的域名 secure=False, https传输 httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
def logout(request): rep = redirect("/login/") rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值 return rep
设置djanjo
操作session
,session保存用户信息需要一张表。django_session
需要提前执行数据库迁移命令。不然找不到那张表数据没法保存。
注意:django默认的session失效时间是14天 客户端会接收到的键值对,键默认是sessionid值是加密的随机字符串(令牌)
.
def set_session(request): request.session['name'] = 'xz' return HttpResponse('设置session') def get_session(request): print(request.session.get('name')) return HttpResponse('获取session')
.
request.session['name'] = 'jason' 1.django自动产生一个随机字符串返回给客户端(对name加密) 2.往django_session创建数据(对xz加密) request.session.get('name') 1.自动重启请求中回去sessionid对应的随机字符串 2.拿着随机字符串去django_session中匹配数据 3.如果匹配上还会自动解密数据并展示
.
# 删除当前会话的所有Session数据 request.session.delete() # 删除当前的会话数据并删除会话的Cookie。 request.session.flush() request.session.set_expiry(value) *如果value是个整数,session会在些秒数后失效 *如果value是个datatime或timedelta,session就会在这个时间失效 *如果value是个0,用户关闭浏览器session就会失效 *如果value是个None,session会依赖全局session失效策略
from functools import wraps def check_login(func): @wraps(func) def inner(request, *args, **kwargs): next_url = request.get_full_path() if request.session.get("user"): return func(request, *args, **kwargs) else: return redirect("/login/?next={}".format(next_url)) return inner def login(request): if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") if user == "xz" and pwd == 123: # 设置session request.session["user"] = user # 获取跳到登陆页面之前的URL next_url = request.GET.get("next") # 如果有,就跳转回登陆之前的URL if next_url: return redirect(next_url) # 否则默认跳转到index页面 else: return redirect("/index/") return render(request, "login.html") @check_login def logout(request): # 删除所有当前请求相关的session request.session.delete() return redirect("/login/") @check_login def index(request): current_user = request.session.get("user", None) return render(request, "index.html", {"user": current_user})
官方说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
中间件帮助我们在视图函数中执行之后都可以做一些额外的操作。
django中间件类似于django的门户,所有的请求很响应走都必须经过中间件。
django默认自带七个中间件,每个中间件都有各自负责的功能
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', ]
除了默认的之外还支持自定义中间件(无限加中间件)
中间件使用场景
全局相关的功能:全局用户身份校验,全局用户黑名单校验,全局用户访问频率校验
django自定义中间件中有五种方法
process_request process_response process_view process_template_response process_exception
方法 | 说明 |
---|---|
process_request | 1.请求来的时候会按照配置文件中注册了中间件, 从上往下依次执行每个中间件里面的process_request方法, 如果没有则直接跳过。 2.该方法如果返回了HttpResonse对象,那么请求不会再往后执行,原路返回 |
process_response | 1.响应走的时候会按照配置文件注册了的中间件, 从下往上依次执行每个中间件里面process_response方法, 如果没有则直接跳过。 2.该方法有两个形参request和response,并且默认情况下返回response。 3.该方法也可以自己返回HttpResponse对象,相当于狸猫换太子。 |
process_view | 当路由匹配成功之后,执行视图函数之前,自动触发。 |
process_template_response(了解) | 当视图函数返回的数据对象中含有render属性对应render函数才会触发。 |
process_exception(了解) | 当视图函数报错之后,自动触发。 |
注意:如果请求的过程中process_request
方法直接返回了HttpResponse
对象那么会原地执行同级别process_response
方法返回(flask
则不同)。
eg:创建一个文件夹utils里面是mymdd.py文件
class MyMdd1(MiddlewareMixin): def process_request(self, request): print('MyMdd1 process_request') #如果请求有问题就可以直接返回HttpResponse的对象。退回去,就不会执行后面的内容了 # return HttpResponse("我怀疑你有问题 你赶紧滚蛋!") def process_response(self, request, response): print('MyMdd1 process_response') return response # return HttpResponse('狸猫换太子') def process_view(self, request, view_func, view_args, view_kwargs): print('MyMdd1 process_view') def process_exception(self,request, exception): print(exception) print('MyMdd1 process_exception') def process_template_response(self, request, response): print('MyMdd1 process_template_response') return response class MyMdd2(MiddlewareMixin): def process_request(self, request): print('MyMdd2 process_request') def process_response(self, request, response): print('MyMdd2 process_response') return response def process_view(self, request, view_func, view_args, view_kwargs): print('MyMdd2 process_view')
注意:
1.对于process_response、process_template_response必须要返回一个形参response。 不然返回的数据为空,没有返回的结果。 2.针对视图函数有render方法,才能触发process_template_response中间件。
def get_md(request): print('from get_md') def render(): return HttpResponse("hahaha") obj = HttpResponse('嘿嘿嘿') obj.render = render return obj