会话保持
会话
- 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
- HTTP协议是无状态的,导致会话状态难以保护
- cookies和session就是为了保持会话状态而诞生的两个储存技术
Cookies
cookies是保存在客户端浏览器上的存储空间
- cookies在浏览器上是以键值对的形式进行存储的,键和值都是ASCII字符串的形式存储(没有中文)
- 是有存储周期的
- cookies中的数据都是按域存储隔离的,不同域之间无法访问
- cookies的内部数据会在每次访问此网址时都会携带到服务器端,如果+ cookies过大会降低响应速度
-
使用
HttpResponse.set_cookie(key,value='', max_age = None, expires = None) # key cookie的名字 # value cook的值 # max_age cookie存活时间,秒为单位 # expire 具体过期时间 # 不设置max_age和expire时 关闭浏览器就过期 # 两者都是设置超时时间的 并且都是以秒为单位 # 需要注意的是 针对IE浏览器需要使用expires
-
删除和获取
- 删除
HttpResponse.delete_cookie(key)
删除指定key的cookie,如果没有不会发生 - 获取
request.COOKIES
cookies字典
request.COOKIES.get(key)
温柔点的取值
- 删除
-
加盐
salt: 加密盐 -
举例
-
视图view.py
from django.shortcuts import render, redirect, HttpResponse, reverse from django.http import JsonResponse # Create your views here def login_auth(func): def inner(request,*args,**kwargs): # print(request.path_info) # print(request.get_full_path()) target_url = request.get_full_path() if request.COOKIES.get('username'): res = func(request,*args,**kwargs) return res else: return redirect('/login/?next=%s'%target_url) return inner def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == '123' and password == '123': next_url = request.GET.get('next') if next_url: obj = redirect(next_url) else: obj = redirect('/home/') obj.set_cookie('username','123') return obj return render(request,'login.html') @login_auth def home(request): return HttpResponse('home页面,只有登录之后才能进来') @login_auth def index(request): return HttpResponse('index页面,只有登录之后才能进来') @login_auth def login_out(request): obj = redirect('/login/') obj.delete_cookie('username') return obj
-
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <h1 class="text-center">登录</h1> <form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username" class="form-control"></p> <p>password:<input type="text" name="password" class="form-control"></p> <input type="submit" class="btn btn-success"> </form> </body> </html>
-
Session
session数据是保存在服务端的,给客户端返回的是一个随机字符串客户端 sessionid:随机字符串
浏览器向服务器提交数据,然后生成session存在数据库,并将sessionid 返回给浏览器,然后浏览器将sessionid作为cookie保存。每个客户端在服务器端有一个独立的session
-
session配置
-
在INSTALLED_APPS中添加
django.contrib.sessions
-
在MIDDLEWARE中添加
django.contrib.sessions.middleware.SessionMiddleware
-
修改sessionid的名字:
SESSION_COOKIE_NAME = "mysession"
-
settings.py其余配置
# session 设置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(数字为秒数)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
注意:
- 在settings.py文件任意位置(推荐底部,方便查找)添加即可
- 如果设置的是默认参数,那么可以比用添加到 settings.py中,比如说我想设置Session的失效日期为1天,那么我只需要在settings.py文件下添加·SESSION_COOKIE_AGE = 86400即可。
- ESSION_SAVE_EVERY_REQUEST = True和SESSION_EXPIRE_AT_BROWSER_CLOSE = True 需同时设置,否则会导致过期时间无法生效
-
-
数据库迁移命令
在默认情况下操作session的时候需要django默认的一张django_session表python manage.py makemigrations python manage.py migrate
-
session的使用
session对象是一个类似于字典的sessionstore类型的对象,可以用类似于字典的方式操作
session能存储字符串,整形,字典,列表等-
设置过期时间
request.session.set_expiry() # 整数 : 多少秒 # 日期对象 : 到指定日期就失效 # 0 : 一旦当前浏览器窗口关闭立刻失效 # 不写 : 失效时间就取决于django内部全局session默认的失效时间
-
保存session的值到服器
-
代码
request.session['key'] = value # def set_session(request): # request.session['name'] = 'www' # return HttpResponse('666')
-
此时django内部
- django内部会自动帮你生成一个随机字符串
- django内部自动将随机字符串和对应的数据存储到django_session表中
- 先在内存中产生操作数据的缓存
- 在响应结果django中间件的时候才真正的操作数据库
- 将产生的随机字符串返回给客户端浏览器保存
-
-
获取session的值
- 代码
value = request.session['key']
value = request.session.get('key',默认值)
- 此时Django内部
- 自动从浏览器请求中获取sessionid对应的随机字符串
- 拿着该随机字符串去django_session表中查找对应的数据
- 如果比对上了 则将对应的数据取出并以字典的形式封装到request.session中
- 如果比对不上 则request.session.get()返回的是None
- 代码
-
删除session
-
request.session.delete() # 只删服务端的 客户端的不删
-
request.session.flush() # 浏览器和服务端都清空(推荐使用)
示例:def del_session(request): request.session.flush() # request.session.delete() return HttpResponse('666')
-
-
-
session的保存位置
session是保存在服务端的 但是session的保存位置可以有多种选择- MySQL
- 文件
- redis
- memcache
-
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(数据库和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中的Session配置
1. 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) 1. 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 1. 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 1. 缓存+数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 1. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 其他公用设置项: SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
-
session的其他问题
- Django_session表是单表设计,随着用户增多,内容会慢慢增加的,而且过期与删除后不会自动删除数据
- 可以每晚执行
python mange.py clearsessions
【可以删除已经过期的session数据】
缓存
-
缓存
-
定义:缓存是一类可以更快的读取数据的介质的统称,也指其他可以加快数据读取的存储方式,一般用来存储临时数据,常用介质是读取速度很快的内存
-
意义:视图渲染有一定的成本,数据库的频繁查询过高;所以对于低频变动的页面可以考虑使用缓存技术,减少实际渲染次数,用户拿到响应的时间成本会更低
-
案例分析:
from django.shortcuts import render def index(request): #时间复杂度极高的渲染 book_list = Book.objects.all() #-> 此处假设用时2s return render(request,'index.html',local()) #此处的页面渲染会在book_list查询到结果后才执行
-
优化思想:(转至官网)
given a URL, try finding that page in the cache if the page is in the cache: return the cached page else: generate the page save the generated page in the cache (for next time) return the generated page
-
缓存应用场景:
- 博客列表页
- 电商商品详情页
- 场景特点:缓存的地方,数据变动频率小
-
-
django中设置缓存 - 数据库缓存
-
将缓存的数据存储在数据库中
-
说明:尽管存储的介质没有更换,但是当把一次负责查询的结果直接存储到另一张表里,比如多个条件的过滤查询结果,可避免重复进行复杂查询,提升效率。
-
设置settings.py,添加CACHES配置
CACHES = { 'default':{ 'BACKEND':'django.core.cache.backends.db.DatabaseCache', #引擎 'LOCATION':'my_cache_table',#设置缓存使用的数据表,设置表名为:my_cache_table 'TIMEOUT':300 #设置缓存保存时间 单位秒,默认值为300 'OPTIONS':{ 'MAX_ENTRIES':300, #缓存最大数据条数 'CULL_FREQUENCY':2 #缓存达到最大条数时,删除1/X的缓存条数 } } }
-
注:数据库缓存所使用的数据表需要手动创建,进入django shell执行python manage.py createcachetable,表名为CACHES里面设置的表名
-
数据库迁移后会在数据库中自动生成my_cache_table数据表,数据表中字段:
- cache_key: 缓存的键
- value: 缓存的值
- expires: 缓存的过期时间
-
-
django中设置缓存 - 本地内存缓存
-
数据缓存到服务器内存中
-
配置样例:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', #内存寻址 - 使用的是雪花算法 } }
-
-
django中设置缓存 - 文件系统缓存
-
将缓存的数据存储到本地文件中
-
配置样例:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', #缓存文件夹的路径 # 'LOCATION': 'c:\test\cache', #windows 下示例 } }
-
-
django中使用缓存 - 整体缓存策略
-
在视图函数中:将整个视图函数全部缓存到数据库中,如需对某个视图进行增加缓存,直接在该视图上使用cache_page装饰器即可
from django.views.decorators.cache import cache_page @cache_page(30) -> 单位s,当前视图缓存有效期 def my_view(request):
-
逻辑:第一次请求时将该视图的整个response存入到缓存中,下一次请求时就先检查缓存中是否有需要的response,如果有则不再进入视图函数中处理。
-
在路由中:在需要增加缓存的视图调用位置增加缓存
from django.views.decorators.cache import cache_page urlpatterns = [ path('page/',cache_page(60)(my_view)),#逻辑与在试图函数中使用相同 ]
-
缺点:
- 当对整个视图函数进行缓存后,下一次请求时,缓存未过期,请求数据会直接走缓存,如果视图函数中有相关权限校验,则无法进行校验(如:博客网站,博主访问后会将私有博客、公有博客一并进入缓存,访客直接访问的话就不会走视图函数进行身份验证,也能访问到博客的私有博客);
- 删除缓存成本过高,几乎无法得知缓存的key,无法进行主动删除,容易导致出现新旧数据不一致的情况(编辑后的数据无法及时更新到缓存中去)
-
-
django中使用缓存 - 局部缓存
-
使用缓存API引入
-
方式一:使用caches[‘CACHE配置key’] 导入具体对象
from django.core.cache import caches cache1 = caches['default'] #default -> settings文件中配置的CACHES的键名 cache2 = caches['myalias']
-
方式二:直接导入CACHES配置项中的‘default’项:
from django.core.cache import cache
-
-
缓存API相关方法:
作用 参数 返回值 cache.set(key,value,timeout) 存储缓存 key : 缓存的key,字符串类型 value : python对象 timeout : 缓存存储时间(s),默认为CACHES中的TIMEOUT值 cache.get(key) 获取缓存 key : 缓存的key,字符串类型 cache.add(key, value) 存储缓存,只在key不存在时生效 key : 缓存的key,字符串类型 value : python对象 cache.get_or_set(key,value,timeout) 如果未获取到数据则执行set操作 key : 缓存的key,字符串类型 value : python对象 timeout : 缓存存储时间(s),默认为CACHES中的TIMEOUT值 cache.set_many(dict,timeout) 批量存储缓存 dict : 缓存的key和value的字典 timeout : 缓存时间(s) cache.get_many(key_list) 批量获取缓存 key_list : 包含key的列表 cache.delete(key) 删除key的缓存数据 key : 缓存的key,字符串类型 cache.delete_many(key) 批量删除缓存 key_list : 包含key的列表
-
-
浏览器缓存策略
-
强缓存:不会向服务器发送请求,直接从缓存中读取资源
- 响应头 - Expires
- 定义:缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点
- 样例:Expires : Thu,02 Apr 2030 05:14:08 GMT
- 响应头 - Cache-Control
- 作用:在HTTP/1.1 中,Cache-Control主要用于控制网页缓存,比如当Cache-Control:max-age=120 代表请求创建时间后的120秒,缓存失效
- 说明:目前服务器都会带着这两个头同时响应给浏览器,浏览器优先使用Cache-Control
- 响应头 - Expires
-
协商缓存 -> 在强缓存的基础上衍生出来的
- 强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据;当强缓存的数据是一些静态文件、大图片等这类比较费带宽且不易变化的数据,强缓存到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果文件不可用,则返回最新数据
- 响应头:Last-Modified 和 If-Modifield-Since 请求头
- 说明:
- Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存
- 当缓存到期后,浏览器将获取到的Last-Modified值作为请求头If-Modifield-Since的值,与服务器发请求协商,服务端返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]
- 缺点:不够精确,Last-Modified是根据修改时间来进行判断缓存是否可继续使用,单位为秒;如果文件的修改时间极短,Last-Modified就发现不了文件已经更改
- 说明:
- 响应头 ETag响应头和If-None-Match 请求头
- 说明:
- ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,ETag就会重新生成(唯一标识为哈希值)
- 缓存到期后,浏览器将ETag响应头的值作为If-None-Match请求头的值,给服务器发请求协商;服务器接到请求头后,比对文件标识,不一致则认为资源不可用,返回200响应码代表缓存不可用[响应体为最新资源],可用则返回304响应码
- 缺点:请求时会对文件计算哈希值,会占用计算资源
- 说明:
-