Django的会话保持

会话保持

会话

  • 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
  • HTTP协议是无状态的,导致会话状态难以保护
  • cookies和session就是为了保持会话状态而诞生的两个储存技术

Cookies

cookies是保存在客户端浏览器上的存储空间

  • cookies在浏览器上是以键值对的形式进行存储的,键和值都是ASCII字符串的形式存储(没有中文)
  • 是有存储周期的
  • cookies中的数据都是按域存储隔离的,不同域之间无法访问
  • cookies的内部数据会在每次访问此网址时都会携带到服务器端,如果+ cookies过大会降低响应速度
  1. 使用

    HttpResponse.set_cookie(key,value='', max_age = None, expires = None)
    # key cookie的名字
    # value cook的值
    # max_age cookie存活时间,秒为单位
    # expire 具体过期时间
    # 不设置max_age和expire时 关闭浏览器就过期
    # 两者都是设置超时时间的 并且都是以秒为单位
    # 需要注意的是 针对IE浏览器需要使用expires
    
  2. 删除和获取

    1. 删除
      HttpResponse.delete_cookie(key)
      删除指定key的cookie,如果没有不会发生
    2. 获取
      request.COOKIES cookies字典
      request.COOKIES.get(key) 温柔点的取值
  3. 加盐
    salt: 加密盐

  4. 举例

    1. 视图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
      
    2. 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>
      

      login.html

Session

session数据是保存在服务端的,给客户端返回的是一个随机字符串客户端 sessionid:随机字符串
浏览器向服务器提交数据,然后生成session存在数据库,并将sessionid 返回给浏览器,然后浏览器将sessionid作为cookie保存。每个客户端在服务器端有一个独立的session

  1. session配置

    1. 在INSTALLED_APPS中添加django.contrib.sessions

    2. 在MIDDLEWARE中添加django.contrib.sessions.middleware.SessionMiddleware

    3. 修改sessionid的名字:
      SESSION_COOKIE_NAME = "mysession"

    4. 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 需同时设置,否则会导致过期时间无法生效
  2. 数据库迁移命令
    在默认情况下操作session的时候需要django默认的一张django_session表

    python manage.py makemigrations
    python manage.py migrate
    
  3. session的使用
    session对象是一个类似于字典的sessionstore类型的对象,可以用类似于字典的方式操作
    session能存储字符串,整形,字典,列表等

    • 设置过期时间

      request.session.set_expiry()
      # 整数 : 多少秒
      # 日期对象 : 到指定日期就失效
      # 0 : 一旦当前浏览器窗口关闭立刻失效
      # 不写 : 失效时间就取决于django内部全局session默认的失效时间
      
    • 保存session的值到服器

      1. 代码

        request.session['key'] = value 
        # def set_session(request):
        #    request.session['name'] = 'www'
        #    return HttpResponse('666')
        
      2. 此时django内部

        1. django内部会自动帮你生成一个随机字符串
        2. django内部自动将随机字符串和对应的数据存储到django_session表中
          1. 先在内存中产生操作数据的缓存
          2. 在响应结果django中间件的时候才真正的操作数据库
        3. 将产生的随机字符串返回给客户端浏览器保存
    • 获取session的值

      1. 代码
        value = request.session['key']
        value = request.session.get('key',默认值)
      2. 此时Django内部
        1. 自动从浏览器请求中获取sessionid对应的随机字符串
        2. 拿着该随机字符串去django_session表中查找对应的数据
        3. 如果比对上了 则将对应的数据取出并以字典的形式封装到request.session中
        4. 如果比对不上 则request.session.get()返回的是None
    • 删除session

      • request.session.delete() # 只删服务端的 客户端的不删

      • request.session.flush() # 浏览器和服务端都清空(推荐使用)
        示例:

        def del_session(request):
           request.session.flush()
           # request.session.delete()
           return HttpResponse('666')
        
  4. session的保存位置
    session是保存在服务端的 但是session的保存位置可以有多种选择

    • MySQL
    • 文件
    • redis
    • memcache
  5. 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失效策略。
    
  6. 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,默认修改之后才保存(默认)
    
  7. session的其他问题

    1. Django_session表是单表设计,随着用户增多,内容会慢慢增加的,而且过期与删除后不会自动删除数据
    2. 可以每晚执行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
      
    • 缓存应用场景:

      1. 博客列表页
      2. 电商商品详情页
      3. 场景特点:缓存的地方,数据变动频率小
  • 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)),#逻辑与在试图函数中使用相同
      ]
      
    • 缺点:

      1. 当对整个视图函数进行缓存后,下一次请求时,缓存未过期,请求数据会直接走缓存,如果视图函数中有相关权限校验,则无法进行校验(如:博客网站,博主访问后会将私有博客、公有博客一并进入缓存,访客直接访问的话就不会走视图函数进行身份验证,也能访问到博客的私有博客);
      2. 删除缓存成本过高,几乎无法得知缓存的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 请求头
        • 说明:
          1. Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存
          2. 当缓存到期后,浏览器将获取到的Last-Modified值作为请求头If-Modifield-Since的值,与服务器发请求协商,服务端返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]
        • 缺点:不够精确,Last-Modified是根据修改时间来进行判断缓存是否可继续使用,单位为秒;如果文件的修改时间极短,Last-Modified就发现不了文件已经更改
      • 响应头 ETag响应头和If-None-Match 请求头
        • 说明:
          1. ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,ETag就会重新生成(唯一标识为哈希值)
          2. 缓存到期后,浏览器将ETag响应头的值作为If-None-Match请求头的值,给服务器发请求协商;服务器接到请求头后,比对文件标识,不一致则认为资源不可用,返回200响应码代表缓存不可用[响应体为最新资源],可用则返回304响应码
        • 缺点:请求时会对文件计算哈希值,会占用计算资源
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值