从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话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
Title 登录
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文件redismemcache
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:testcache', #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
协商缓存 -> 在强缓存的基础上衍生出来的
强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据;当强缓存的数据是一些静态文件、大图片等这类比较费带宽且不易变化的数据,强缓存到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果文件不可用,则返回最新数据响应头:Last-Modified 和 If-Modifield-Since 请求头
说明:
- Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存当缓存到期后,浏览器将获取到的Last-Modified值作为请求头If-Modifield-Since的值,与服务器发请求协商,服务端返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]
说明:
- ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,ETag就会重新生成(唯一标识为哈希值)缓存到期后,浏览器将ETag响应头的值作为If-None-Match请求头的值,给服务器发请求协商;服务器接到请求头后,比对文件标识,不一致则认为资源不可用,返回200响应码代表缓存不可用[响应体为最新资源],可用则返回304响应码



