59 Cookie 与 Session

Cookie

Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。

客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。

当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!

Cookie与HTTP头

Cookie是通过HTTP请求和响应头在客户端和服务器端传递的: 

  • Cookie:请求头,客户端发送给服务器端; 
  • 格式:Cookie: a=A; b=B; c=C。即多个Cookie用分号离开;  Set-Cookie:响应头,服务器端发送给客户端; 
  • 一个Cookie对象一个Set-Cookie: Set-Cookie: a=A Set-Cookie: b=B Set-Cookie: c=C  

Cookie的覆盖 

如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。 

django中的cookie语法

1.cookie:
  1.每一个客户端浏览器针对每一个服务器维持信息的一个键值对结构
  2.信息保存在客户端
  3.每次发请求都会带着这个类似于字典的结构
  4.服务器可以读写cookie字典

2.设置cookie

响应对象:rep =HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()
响应对象.set_cookie("k1","v1",时间)

rep.set_cookie(key,value,时间)

rep.set_signed_cookie(key,value,salt='加密盐',...) 

3.获取cookie

  request.COOKIES

  value = request.COOKIES.get(key)

 4.删除cookie

  response.delete_cookie("cookie_key",path="/",domain=name)

'''
class HttpResponseBase:

        def set_cookie(self, key,                 键
                     value='',            值
                     max_age=None,        超长时间 
                              cookie需要延续的时间(以秒为单位)
                              如果参数是 None`` ,这个cookie会延续到浏览器关闭为止。

                     expires=None,        超长时间
                                 expires默认None ,cookie失效的实际日期/时间。 
                                

                     path='/',           Cookie生效的路径,
                                                 浏览器只会把cookie回传给带有该路径的页面,这样可以避免将
                                                 cookie传给站点中的其他的应用。
                                                 / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
                     
                             domain=None,         Cookie生效的域名
                                                
                                                  你可用这个参数来构造一个跨站cookie。
                                                  如, domain=".example.com"
                                                  所构造的cookie对下面这些站点都是可读的:
                                                  www.example.com 、 www2.example.com 
                                 和an.other.sub.domain.example.com 。
                                                  如果该参数设置为 None ,cookie只能由设置它的站点读取。

                     secure=False,        如果设置为 True ,浏览器将通过HTTPS来回传cookie。
                     httponly=False       只能http协议传输,无法被JavaScript获取
                                                 (不是绝对,底层抓包可以获取到也可以被覆盖)
                  ): pass

'''
复制代码
获取cookie:
cookie源码

5.登录时cookie的应用

def login(request):

    if request.method=="GET":
        return render(request,"login.html")
    else:
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        user_obj=UserInfo.objects.filter(name=user,pwd=pwd).first()
        if user_obj:
            # obj=HttpResponse("登录成功!")
            obj=redirect("/index/") #登录成功,重定向到index首页
            obj.set_cookie("is_login",True,20) #设置cookie
            obj.set_cookie("username",user) #设置cookie
        
            return obj
        return HttpResponse("Error!")

def index(request):

    print("request.COOKIES",request.COOKIES)
    is_login=request.COOKIES.get("is_login")#获取cookie
    username=request.COOKIES.get("username") #获取cookie

    if not is_login: # 未登陆过
        return redirect("/login/")

    return render(request,"index.html",{"username":username})

 Session

seesion为服务端技术,  服务器在运行时可以 为每一个用户的浏览器创建一个其独享的session对象,由于 session为用户浏览器独享,所以用户在访问服务器的web资源时 ,可以把各自的数据放在各自的session中,当用户再去访问该服务器中的其它web资源时,其它web资源再从用户各自的session中 取出数据为用户服务。

1.Django中session语法

1、设置Sessions值
          request.session['session_name'] ="admin"
2、获取Sessions值
          session_name = request.session["session_name"]
3、删除Sessions值
          del request.session["session_name"]
4、flush()
     删除当前的会话数据并删除会话的Cookie。
     这用于确保前面的会话数据不可以再次被用户的浏览器访问
            
5、get(key, default=None)
  
fav_color = request.session.get('fav_color', 'red')
  
6、pop(key)
  
fav_color = request.session.pop('fav_color')
  
7、keys()
  
8、items()
  
9、setdefault()
  
 
10 用户session的随机字符串
        request.session.session_key
   
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
   
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
   
        # 删除当前用户的所有Session数据
        request.session.delete("session_key")
   
        request.session.set_expiry(value)
            * 如果value是个整数,session会在些秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。
View Code

2.session 技术流程

1.写session
  request.session["k"]=v
  过程:
    1.创建随机字符串

    2.在django-session表中创建记录
      session-key     session-data
      随机字符串       {“k":"v1"}

    3.响应对象.set_cookie("sessionid",随机字符串)

2.读session
  request.session.get("k")
  过程:
    1.取钥匙 request.COOKIES.get('sessionid')
    2.在django-session表中查询记录:session-key=钥匙
    3.通过对象.k将值返回

3.删session

  request.session.flush()
  过程:
    1.取钥匙 request.COOKIES.get("sessionid")
    2.在django-session表中查询记录:seesion-key=钥匙
    3.对象删除

3.session 的应用 图片验证的生成

用图片PIL 时,需要先安装  pillow 模块    ,  pip  install   pillow 

过程简单分析:

  1.  客户访问login页面  login页面一加载, 遇到  <img src="/verify/" alt="" width="120px" height="40px">,向服务端发请求,到  "/verify/"路径

  2.后端 django  路由中,走path("verify/" , views.verify)

  3. 走 视图函数中:verify 函数,该函数通过一系列处理,得到一个验证码图片数据

1.前端login页面:

<body>
{% csrf_token %}
<div class="nav">图书管理系统</div>

<div class="login">
        <div class="head"><h3>登录页面</h3></div>
        <div class="username">

            <label for="username">用户名:</label>
            <input type="text" class="user"  id="user" name="username" placeholder="请输入用户名">
        </div>

        <div class="pwd">
            <label for="password">&nbsp;&nbsp;&nbsp;:</label>
            <input type="text" class="" name="password" placeholder="请输入密码" id="password" >
        </div>
        <div class="verify">
            <label for="verify">验证码:</label>
            <input type="text" name="verify" id="verify"><img src="/verify/" alt="" width="120px" height="40px">

        </div>
        <div class="error"></div>
        <div class="btn" >
            登录
        </div>

</div>


<script>
    $(".btn").click(function () {
        username = $("#user").val();
        password = $("#password").val();
        verify = $("#verify").val();
        $.ajax({
            url:"/login/",
            data:{
                username:username,
                password:password,
                verify:verify,
                "csrfmiddlewaretoken":$('[name="csrfmiddlewaretoken"]').val()
            },
            type:"post",
            success:function (res) {
                res = JSON.parse(res);
                if (res["user"]){
                    //登录成功,跳转到books 页面
                    location.href="/books/";

                }else {
                    //登录失败
                    $(".error").html(res["msg"]).css("color","red");
                    //1秒钟或提示语句消失,设置定时器
                    setTimeout(function () {
                        $(".error").html("");
                    },2000)

                }

            }

        })
        }
    )
</script>
View Code

2.后端路由

urlpatterns = [
    path('admin/', admin.site.urls),

    path('books/', views.books),
    path('login/',views.login),
    path('verify/',views.verify),
    path('books/add/', views.add),
    re_path('books/del/(d+)/', views.delbook),
    re_path('books/edit/(d+)/', views.edit),
    re_path('del_a/', views.del_a),


]

3.后端 视图

def verify(request):
    #方式一
    import PIL
    from PIL import Image
    # img = Image.new("RGB",(120,40),get_random_color())
    # f = open("verify.png","wb")
    # img.save(f,"png")
    # with open("verify.png","rb") as f:
    #     data =f.read()
    # return HttpResponse(data)

    #方式二:
    # from io import BytesIO
    # img = Image.new("RGB",(120,40),get_random_color())
    # f = BytesIO()
    # img.save(f,"png")
    # data = f.getvalue()
    # return HttpResponse(data)

    # 方式3
    from io import BytesIO
    from PIL import ImageDraw,ImageFont
    img = Image.new("RGB",(120,40),get_random_color())
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("static/font/kumo.ttf",28)
    keep_str=""
    for i in range(5):
        random_num =str(random.randint(0,9))#随机数字
        random_low_alpha =chr(random.randint(97,122)) #随机小写字母
        random_upper_alpha =chr(random.randint(65,90)) #随机大写字母
        random_char=random.choice([random_num,random_low_alpha,random_upper_alpha])#从列表中随机选一个
        #text((x轴坐标值,y轴坐标值),要写的内容,随机颜色,font=字体形式)
        draw.text((20+i*20,0),random_char,get_random_color(),font=font)
        #拼接随机字符串
        keep_str+=random_char

    print(keep_str)
    #set值session 值, key_str =为随机字符串,供用户登录输入验证码的值和这个随机字符串做比对验证
    request.session["keep_str"]=keep_str
    # 噪点噪线
    # width=250
    # height=40
    # for i in range(10):
    #     x1=random.randint(0,width)
    #     x2=random.randint(0,width)
    #     y1=random.randint(0,height)
    #     y2=random.randint(0,height)
    #     draw.line((x1,y1,x2,y2),fill=get_random_color())
    #
    # for i in range(100):
    #     draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())

    f= BytesIO()
    img.save(f,"png")

    data =f.getvalue()

    #返回的数据直接在前端img    <img src="/视图函数/" alt="" width="120px" height="40px">
    # 返回的数据直接在前端img    <img src="/verify/" alt="" width="120px" height="40px">
    return HttpResponse(data)
View Code

6.session 的源码分析过程

中间件
  
        解析session中间件:
             class SessionMiddleware(MiddlewareMixin):
                    def __init__(self, get_response=None):
                        self.get_response = get_response
                        engine = import_module(settings.SESSION_ENGINE)
                        self.SessionStore = engine.SessionStore

                    def process_request(self, request):
                        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
                        request.session = self.SessionStore(session_key)

                    def process_response(self, request, response):pass
            
            一旦请求发生:
            (1)  执行process_request:
                     确定这次是否有sessionid对应的cookie值,赋值给self._session_key 
                     request.session是SessionStore类的实例对象
                     
            (2)
                def  视图函数:
                      request.session["k1"]="v1"
                      request.session["k2"]="v2"
                      
                def 视图函数2:
                      request.session.get("k1")
                
                调用的request.session对象的setitem方法: 
                
                
                class SessionBase():
                
                    def __setitem__():
                        self._session[key] = value
                        self.modified = True
                    
                    _session = property(_get_session)                    
                    def _get_session(self, no_load=False):
     
                        self.accessed = True
                        try:
                            return self._session_cache
                        except AttributeError:
                            if self.session_key is None or no_load:
                                self._session_cache = {}
                            else:
                                self._session_cache = self.load()
                        return self._session_cache
                        
                        
            (3) 执行 process_response:
                        request.session.save()
                        
                        def save():
                        
                            # 创建随机字符串:
                            self._session_key = self._get_new_session_key()
                            # 创建对讲或者更新对象
                            self.model(
                                        session_key=self._get_or_create_session_key(),
                                        session_data=self.encode(data),
                                        expire_date=self.get_expiry_date(),
                                        )
                                                        
                        # 设置cookie
                        response.set_cookie(
                            settings.SESSION_COOKIE_NAME,
                            request.session.session_key, max_age=max_age,
                            expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
                            path=settings.SESSION_COOKIE_PATH,
                            secure=settings.SESSION_COOKIE_SECURE or None,
                            httponly=settings.SESSION_COOKIE_HTTPONLY or None,
                            samesite=settings.SESSION_COOKIE_SAMESITE,
                        )
session源码解析过程
原文地址:https://www.cnblogs.com/knighterrant/p/10249729.html