10.Cookie和Session

1.状态保持

1 状态保持

我们需要先了解一下什么是会话,可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应.例如你给 10086 打个电话,你就是客户端,而 10086 服务人员就是服务器了.从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束.在通话过程中,你会向 10086 发出多个请求,那么这多个请求都在一个会话中.
在 JavaWeb 中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束。
在一个会话的多个请求中共享数据,这就是会话跟踪技术。例如在一个会话中的请求如下:请求银行主页;

  • 请求登录(请求参数是用户名和密码);
  • 请求转账(请求参数与转账相关的数据);
  • 请求信誉卡还款(请求参数与还款相关的数据)。

在这上会话中当前用户信息必须在这个会话中共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款,这就说明我们必须在一个会话过程中有共享数据的能力。

2 怎样实现状态保持

  • 浏览器请求服务器是无状态的,HTTP协议是无状态协议。
  • 无状态:指一次用户请求时,浏览器,服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
  • 无状态原因:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
  • 有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
  • 实现状态保持主要有两种方式:
    • 在客户端存储信息使用Cookie
    • 在服务器端存储信息使用Session

2.Cookie

2.1 什么叫 Cookie

Cookie 翻译成中文是小甜点,小饼干的意思.在 HTTP 中它表示服务器送给客户端浏览器的小甜点.其实 Cookie 是 key-value 结构,类似于一个 python 中的字典.随着服务器端的响应发送给客户端浏览器.然后客户端浏览器会把 Cookie 保存起来,当下一次再访问服务器时把 Cookie 再发送给服务器. Cookie 是由服务器创建,Cookie 是通过 HTTP 请求和响应头在客户端和服务器端传递的一个键值对.客户端会保存 Cookie,并会标注出 Cookie 的来源(哪个服务器的 Cookie)当客户端向服务器发出请求时会把所有这个服务器 Cookie 包含在请求中发送给服务器,这样服务器就可以识别客户端了!

2.2 Cookie特点

HTTP 的 Cookie 规范浏览器规范
Cookie 大小上限为 4KBCookie 大小上限为 8KB
一个服务器最多在客户端浏览器上保存 20 个 Cookie
个浏览器最多保存 300 个 Cookie一个服务器最多在客户端浏览器上保存 500 个 Cookie
Cookie基于域名安全,不同域名的Cookie是不能互相访问的

2.3 cookie 语法

操作例子
设置cookie值response.set_cookie(健,值)
reponse.set_signed_cookie(健,值,salt=‘加密盐’,…)
获取 cookie值request.COOKIES.get(健)
删除 cookie值response.delete_cookie(健,path="/",domain=name)

设置cookie时的参数

参数名含义
max_age超长时间 cookie需要延续的时间(以秒为单位)如果参数是\ None,这个cookie会延续到浏览器关闭为止。
expires超长时间 expires默认None ,cookie失效的实际日期/时间。
pathCookie生效的路径 浏览器只会把cookie回传给带有该路径的页面,这样可以避免将传给站点中的其他的应用 , / 表示根路径,特殊的根路径的cookie可以被任何url的页面访问
domain=NoneCookie生效的域名 你可用这个参数来构造一个跨站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获取
(不是绝对,底层抓包可以获取到也可以被覆盖)

练习

案例 1: 显示上次访问时间。

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

</head>
<body>
<div class="col-md-6 col-md-offset-3">
    <form action="" method="post">
        {% csrf_token %}
        <div class="form-group">
            <label for="user">用户名</label>
            <input type="text" class="form-control" name="user">
        </div>
        <div class="form-group">
            <label for="pwd">密码</label>
            <input type="password" class="form-control" name="pwd">
        </div>
        <input type="submit">
    </form>
</div>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h4>当前时间:{{ now_time }}</h4>
{% if username  %}
    <h3>Hi,{{ username }}</h3>
    <p>上次登陆时间:{{ last_visit_time }}</p>
    <a href="/logout/">注销</a>
{% endif %}
</body>
</html>

view.py

def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        user = User.objects.filter(name=user, pwd=pwd).first()
        if user:
            response = HttpResponse("登录成功!")
            response.set_cookie("is_login", True)
            response.set_cookie("username", user.name, path="/books_app/index")
            return response

    return render(request, "login.html")


def index(request):
    is_login = request.COOKIES.get("is_login")
    if is_login:
        username = request.COOKIES.get("username")
        now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        last_time = request.COOKIES.get("last_visit_time", "")
        response = render(request, "index.html", {"username": username, "last_time": last_time, "now_time": now})
        response.set_cookie("last_visit_time", now)
        return response

    else:
        return redirect("/login/")

案例 2: 显示上次浏览过的商品。

3.session

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

3.1 启用Session

Django项目默认启用Session。

可以在settings.py文件中查看,如图所示
在这里插入图片描述

如需禁用session,将上图中的session中间件注释掉即可。

3.2 存储方式

在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。

3.2.1 数据库

存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式**,Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中

SESSION_ENGINE='django.contrib.sessions.backends.db'

如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-du9McPWt-1615940937363)(session_install-1615901816273.png)]
数据库中的表如图所示
在这里插入图片描述
表结构如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ut83d3pB-1615940937365)(session_desc.png)]

由表结构可知,操作Session包括三个数据:键,值,过期时间。

setting.py文件中的session操作

使用含义
SESSION_COOKIE_NAME=“sessionid”Session的cookie保存在浏览器上
SESSION_COOKIE_PATH="/"Session的cookie保存的路径
SESSION_COOKIE_DOMAIN=NoneSession的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False是否每次请求都保存Session,默认修改之后才保存(默认)
3.2.2 本地缓存

存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'
3.2.3 混合存储

优先从本机内存中存取,如果没有则从数据库中存取。

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
3.2.4 Redis

在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。

网络连接

1) 安装扩展

pip install django-redis

2)配置

在settings.py文件中做如下设置

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

注意

如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误,如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AEfCf0K8-1615940937366)(redis_error.png)]

解决方法:

修改redis的配置文件,添加特定ip地址。

打开redis的配置文件

sudo vim /etc/redis/redis.conf

在如下配置项进行修改(如要添加10.211.55.5地址)

在这里插入图片描述

重新启动redis服务

sudo service redis-server restart

3.3 Session操作

通过HttpRequest对象的session属性进行会话的读写操作。

操作列子
设置Sessions值request.session[‘键’]=值
获取Sessions值request.session.get(‘键’,默认值)
删除Sessions值del request.session[‘键’]
清除session数据,在存储中删除session的整条数据request.session.flush()
清除所有session,在存储中删除值部分request.session.clear()
设置session的有效期request.session.set_expiry(value)
  • 如果value是一个整数,session将在value秒没有活动后过期。

  • 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。

  • 如果value为None,那么session有效期将采用系统默认值, 默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。

练习

1 登录案例

视图函数

def login_session(request):
    """
   实现session的增加和更新
   if request.COOKIE.get("sessionid"):
         则sessionid保持不变,session_data数据更新
   else:
        1.则生成随机字符串sessionid
        2设置cookie,response.set_cookie("sessionid",ltv8zy1kh5lxj1if1fcs2pqwodumr45t)
        3在django—session表中创建一条记录
    """

    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        user = User.objects.filter(name=user, pwd=pwd).first()
        if user:
            now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            request.session["is_login"] = True
            request.session["username"] = user.name
            request.session["last_visit_time"] = now
        return HttpResponse("登录成功!")
    return render(request, "login.html")


def index_session(request):
    """
    实现session的查询
    1.request.COOKIE.get("sessionid")
    2.django-session表中过滤纪录
    3.obj.session_data.get("is_login")
    """
    is_login = request.session.get("is_login")
    if not is_login:
        return redirect("/login_session/")
    username = request.session.get("username")
    last_visit_time = request.session.get("last_visit_time")
    return render(request, "index.html", {"username": username, "last_visit_time": last_visit_time})


def logout(request):
    """
    实现session的删除
    1.random_str=request.COOKIE.get("sessionid")
    2.django_session.objects.filter(session-key=randon_str).delete()
    3.response.delete_cookie("sessionid",random_str_str)
    """
    request.session.flush()
    return redirect("/login/")

模板

参考:前端代码参照案例 1: 显示上次访问时间。

思考: 如果第二个人再次再同一个浏览器上登录,django-session 表会怎样?

2 验证码案例

验证码可以去识别发出请求的是人还是程序!当然,如果聪明的程序可以去分析验证码图片!但分析图片也不是一件容易的事,因为一般验证码图片都会带有干扰线,人都看不清,那么程序一定分析不出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值