Django Cookie和Session

Django Cookie和Session

【一】介绍

【1】起因

  • HTTP协议四大特性
    1. 基于请求响应模式:客户端发送请求,服务端返回响应
    2. 基于TCP/IP之上:作用于应用层之上的协议
    3. 无状态:HTTP协议本身不保存客户端信息
    4. 短链接:1.0默认使用短链接,请求-响应后断开连接
  • 因为无状态
    • 导致客户端和服务端无法正常长时间的通讯
    • 所以需要一种方法来打破这种情况
  • Cookie和Session是Web开发中常用的两种持久化会话状态的方法

【2】Cookie和Session

(1)介绍

  • cookie

    • Cookie是服务器发送到用户浏览器并保存在浏览器 上的一块数据
    • 他会在浏览器下一次向服务器发送请求时被携带并发送到服务器上
  • session

    • Session是另一种保存用户数据的方法,但数据是保存到服务器端
    • Session通过生成一种叫做Session ID唯一标识符,保存在cookie中或者通过URL传递,以便在多个请求中可以识别和跟踪用户

(2)关系

  • session和cookie的主要关系是
    • session通常使用cookie来存储Session ID
    • 以便在多个请求之间跟踪用户
    • 但是也可以通过其他方式(URL)

(3)异同

  • 存储位置:
    • cookie存储在客户端,session存储在服务端
  • 安全性:
    • 由于cookie存在客户端,所以安全性较低
    • 如果信息是密码这种敏感信息,还是用session
  • 生命周期:
    • cookie可以设置过期时间,如果不设置时间,那么关闭浏览器时,cookie就会被删除
    • session的生命周期通常由服务器设置,当用户关闭浏览器并长时间误操作,session也会过期然后删除
  • 存贮容量:
    • cookie的大小通常有限制(4KB)
    • session理论上是没有大小限制的

【二】Django操作cookie

【1】语法

  • 以HttpResponse为例
  • 另外的两把斧也可以

(1)设置cookie

python 复制代码
http_res = HttpResponse()
http_res.set_cookie(key, value)

(2)获取cookie

python 复制代码
request.COOKIES.get(key)

(3)设置过期时间

  • 不指定这个参数的话
    • 那么cookie将是会话Cookie
    • 即在浏览器关闭 后会被删除
  • max_age默认单位是秒
    • 可以使用datetime模块的timedelta快速换算单位
    • max_age = timedelta(days=1).total_seconds()
  • IE浏览器使用expires这个参数
python 复制代码
http_res = HttpResponse()
http_res.set_cookie(key, value, max_age)

(4)注销cookie

python 复制代码
http_res = HttpResponse()
http_res.delete_cookie(key)
  • 视图层
python 复制代码
def get_cookie(request):
    res = request.COOKIES.get("name")
    print(res)
    return HttpResponse(res)

def set_cookie(request):
    http_res = HttpResponse()
    # 浏览器关闭后会被删除
    http_res.set_cookie("name", "bruce")
    # 5秒后这个cookie会被删除
    # http_res.set_cookie("name", "bruce", max_age=5)
    # 注销cookie
    res = http_res.delete_cookie("name")
    print(res)
    return http_res

【2】示例

(1)装饰器登录功能

  • 要求
    • 功能界面func需要登录才可以使用,
      • 如果没有登录就跳转到登录界面
    • 登录完成以后,自动跳转到主页
    • 主页不需要进行登录验证
  • 前端(登录)
    • 其他界面显示文字即可
    • 直接HttpResponse
python 复制代码
<form action="" method="post">
    <p>username: <input type="text" name="username"></p>
    <p>password: <input type="password" name="password"></p>
    <button class="">提交</button>
</form>
  • 视图层
    • login_decorator:登录验证装饰器
    • login:登陆函数
    • home:主界面
    • func1func2功能界面
python 复制代码
def login_decorator(func):
    def inner(request, *args, **kwargs):
        if request.COOKIES.get("login_info"):
            res = func(request, *args, **kwargs)
            return res
        return redirect('/login/')
    return inner

def login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        # 正常需要和数据库数据校验
        # 这里简单一点
        if username == "bruce" and password == "000":
            response = redirect('/home/')
            response.set_cookie("login_info", username + password)
            return response
    return render(request, 'login.html', locals())

def home(request):
    return HttpResponse("主页")

@login_decorator
def func1(request):
    return HttpResponse("func1")

@login_decorator
def func2(request):
    return HttpResponse("func2")

(2)页面跳转登录功能

  • 在原先的基础上
    • 加上那个界面触发的登录
    • 在登录成功以后返回到那个界面
    • 精髓:发送POST请求带上GET请求的内容
python 复制代码
def login_decorator(func):
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.COOKIES.get("login_info"):
            res = func(request, *args, **kwargs)
            return res
        return redirect(f'/login/?next={next_url}')
    return inner


def login(request):
    # http://127.0.0.1:8000/login/?next=/func1/
    # 此时发送的是POST请求
    # 但是携带了get的内容
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        # 正常需要和数据库数据校验
        # 这里简单一点
        if username == "bruce" and password == "000":
            next_url = request.GET.get("next")
            next_url = next_url if next_url else '/home/'
            response = redirect(next_url)
            response.set_cookie("login_info", username + password)
            return response
    return render(request, 'login.html', locals())

【三】Django操作session

【0】准备

  • session是保存在服务器的
  • 那么Django就需要一个文件来保存session数据
  • 这个文件就是在数据迁移时自动创建的表单django_sessoin
  • 即如果新项目想要使用session需要先迁移一下数据

【1】语法

(1)设置session

  • 内部执行过程
    1. 产生一个随机字符串
    2. 保存随机字符串和加密数据
    3. 最后将随机字符串返回给浏览器,存储在cookie中
      • 格式:sessionid:随机字符串
  • 添加多个 键值对数据
    • 最终还是对应一个 sessionid
python 复制代码
request.session['key'] = value

(2)获取session

  • 内部执行过程
    • 获取客户端发来的随机字符串
    • 去存储session的django_sessoin表单中对比查询随机字符串
    • 比对成功自动解密处理数据(根据key找value)
    • 比对失败则request.session中的数据为None
python 复制代码
request.session.get('key')

(3)设置过期时间

  • value是整数:多少秒过期
  • value是日期对象:datetime.datetime 对象,会话将在这个指定的日期和时间过期。
  • value是0:退出浏览器窗口就过期
  • 不设置(None),过期策略将依赖于全局session配置
    • 这是django的settings的文件中的session_cookie_age配置
    • 默认是14天
  • 可以不设置,设置了就必须要给值
  • 过期会删除客户端和服务端的session ,但是
    • 客户端的自动删除了
    • 服务端的出于性能考虑,并不会立即删除过期的session数据。
    • 可以手动clearsessions 命令来手动清理过期的session。
python 复制代码
request.session.set_expiry(value)

(4)清空session

  • delete()
    • 清除 当前用户所在服务端 的session数据
    • 但是会保留 session的键key
    • 如果下次用户来访问时session没有被填充
    • 那么返回的就是一个空的session对象
python 复制代码
request.session.delete()
  • flush()
    • 完全删除当前用户的所有session对象和相关数据
    • 包括服务端和客户端
python 复制代码
request.session.flush()

(5)多值和多session

  • 同一个用户创建多个数据

    • 报错的只有一个sessionid
  • 同一个计算机,同一个浏览器对应相同的sessionid

  • 同一个计算机,不同浏览器对应不同的sessionid

  • 当session过期时,可能出现多个sessionid对应同一个浏览器

    • 但是过期的数据不会持久化存储,会被定时清理掉
    • 目的是为了节省服务器资源
    • 手动清理clearsessions 命令
  • 视图层

python 复制代码
def get_session(request):
    res1 = request.session.get('sign')
    print(f"session第一个数据:{res1}")
    res2 = request.session.get("flag")
    print(f"session第一个数据:{res2}")
    return HttpResponse("获取session成功")


def set_session(request):
    # session添加多个键值对,还是保存在一个sessionid中
    request.session['sign'] = "hello"
    request.session['flag'] = True
    # 十秒后自动清除客户端和服务端的session
    # request.session.set_expiry(10)
    # 关闭浏览器就清除
    # request.session.set_expiry(0)
    return HttpResponse("添加session成功")

【2】Django配置

python 复制代码
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

5. 加密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,默认修改之后才保存(默认)

【3】示例

(1)页面跳转登录

  • 和cookie的基本一样就是cookie改成session
python 复制代码
def login_decorator(func):
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.session.get("login_info"):
            res = func(request, *args, **kwargs)
            return res
        return redirect(f'/login/?next={next_url}')
    return inner


def login(request):
    # http://127.0.0.1:8000/login/?next=/func1/
    # 此时发送的是POST请求
    # 但是携带了get的内容
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        # 正常需要和数据库数据校验
        # 这里简单一点
        if username == "bruce" and password == "000":
            next_url = request.GET.get("next")
            next_url = next_url if next_url else '/home/'
            response = redirect(next_url)
            # response.sess("login_info", username + password)
            request.session['login_info'] = f"{username}-{password}"
            return response
    return render(request, 'login.html', locals())
相关推荐
啦啦右一1 小时前
Spring Boot | (一)Spring开发环境构建
spring boot·后端·spring
森屿Serien1 小时前
Spring Boot常用注解
java·spring boot·后端
盛派网络小助手3 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
算法小白(真小白)3 小时前
低代码软件搭建自学第二天——构建拖拽功能
python·低代码·pyqt
唐小旭3 小时前
服务器建立-错误:pyenv环境建立后python版本不对
运维·服务器·python
007php0073 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
∝请叫*我简单先生3 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
Chinese Red Guest3 小时前
python
开发语言·python·pygame
骑个小蜗牛4 小时前
Python 标准库:string——字符串操作
python