讲完前端之後,就一定要说到 Cookie 跟 Session 这两个东西了,这两个是什麽东西呢?又能干什麽呢?
开始之前,首先要先说到 http 的无状态特性。举个例子,现在在逛网拍,想要把某个商品加入购物车,要入一遍帐号密码;接着要送出订单,又要输入一遍帐号密码;不管做什麽都需要输入一遍帐号密码,为什麽会这样呢?因为 http 没有纪录状态。为了解决这样的问题,所以就出现了 Cookie 跟 Session。
首先先来说 Cookie,Cookie 就像是麦X劳的甜心卡,上面有着资讯(买A送B),甚至会有期限(2021/12/31),并且由商家交给顾客自行留存,且只能在原商店使用。
http 中的 Cookie 也是这样,有 key-value 、期限,同样由 Server 送给浏览器保存,也只能在相同的 Domain(网域) 使用。优点当然是解决了 http 无状态造成的问题;不过缺点则是 Cookie 有可能会被窜改,所以只适合纪录一些不重要的数据(话说根据浏览器不同,有不同的大小及数量的限制。标准^[1]上是每个 Cookie 4096Bytes,最少每个 Domain 要可以有 20 个 Cookie)。
好了,大概了解完 Cookie 了,那麽就来看一下 Flask 中如何设置 Cookie 吧!让我们用继续使用前面的架构,新增几个档案:
ithome
├── static
│ └── logo.svg
├── templates
│ ├── res
│ │ ├── home.html
│ │ └── login.html # 新增它
│ ├── base.html
│ ├── index.html
│ └── page_not_found.htmlindex.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock
举个例子,假设现在要做个登入後要在 Cookie 中设定 username 并回传登入後页面,可以这样写:
login.html
{% extends 'base.html' %}
{% block title %}
template value
{% endblock %}
{% block img %}
<img src={{ url_for('static', filename='logo.svg' ) }} />
{% endblock %}
{% block content %}
<h1>Hello</h1>
<form action={{ url_for('login') }} method="POST">
<fieldset>
<legend>Login</legend>
<label>Username: </label>
<input type="text" name="username" /><br />
<label>Password: </label>
<input type="password" name="password" /><br />
<input type="submit" value="Login" />
</fieldset>
</form>
{% endblock %}
app.py
from flask import redirect, request, make_response, render_template
@app.route('/')
def index():
return render_template('res/index.html')
@app.route('/home', methods=['GET'])
def home():
if 'username' in request.cookies:
user = request.cookies.get('username')
else:
user = None
return render_template('res/home.html', username=user)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET': # 输入网址会进到这里
response = make_response(render_template('res/login.html'))
elif request.method == 'POST': # 表单送出後会到这里
account = request.values.get('username', None)
# 验证是否有这个使用者以及密码是否正确,生出验证结果 auth_result
auth_result = 'success' # 假设成功
''' 建立回应 '''
if auth_result == 'success': # 如果都正确
response = make_response(redirect(url_for('home')))
''' 设定 Cookie '''
response.set_cookie('username', account)
else: # 如果错误
response = make_response(redirect(url_for('login')))
else:
response = make_response(redirect(url_for('index')))
return response
如果实际跑一遍就会像这样:
这样就确定有放上去了。
Cookie 要包在回传的东西里面,在回传给使用者的浏览器设,所以需要使用 Day 19 的 make_response
包进去後再回传。
看到这里应该已经会基础的设定 Cookie 了吧,让我们仔细的看一下还可以设定什麽,set_cookie
所有可以设定的参数如下:
set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, samesite=None)
s
时)时才会被传送。如果现在多了一个页面需要使用到 username,要从 Cookie 取得怎麽办。让我们在做一个页面来实测一下。同样是使用相同的架构,不过又新增了一个档案:
ithome
├── static
│ └── logo.svg
├── templates
│ ├── res
│ │ ├── home.html
│ │ ├── index.html
│ │ ├── login.html
│ │ ├── page_not_found.html
│ │ └── settings.html # 新增它
│ └── base.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock
又举个例子,假设现在要做个登入後使用者要可以有个人设定的页面,可以这样写:
settings.html
{% extends 'base.html' %}
{% block title %}
template value
{% endblock %}
{% block img %}
<img src={{ url_for('static', filename='logo.svg' ) }} />
{% endblock %}
{% block content %}
{% if username %}
<h1>{{ username }}'s settings</h1>
{% else %}
<a href={{ url_for('index') }}><button>Index</button></a>
{% endif %}
{% endblock %}
@app.route('/settings', methods=['GET'])
def settings():
if 'username' in request.cookies:
user = request.cookies.get('username')
else:
user = None
return render_template('res/settings.html', username=user)
如果已经登入过了(因为这边没有设过期时间,所以 Cookie 会一直在,可以手动删除它),Cookie 的 username 还在,那麽 URL 後面直接改成 settings
就可以跳过去了(虽然可以弄一个 link,直接点就过去了),这样就可以抓到 Cookie 的值了。
如果要设定时间可以使用 datetime.datetime.now() + datetime.timedelta(<units>=<number>)
这个方式设定。
最後说一下如何删除,Cookie 如果没有设定时间就会是关闭浏览器的时候删除,有设定时间不会是那个时间删除,而是要重新设定一次过期的时间才会被删除喔。
^[RFC 2965 HTTP State Management Mechanism #5.3]RFC 2965 HTTP State Management Mechanism #5.3
那麽就大概这样,今天本来打算一次讲完 Cookie 跟 Session 的,但是发现讲不完,所以下一篇再讲 Session 吧。
大家掰~掰~
>>: Day 19 Docker Compose 操作指令
struct() 用於建立自定义资料结构的命令,其中可以包含多个不同型别的成员,就像是把多个不同型别...
Python的程序有2种退出方式:os._exit(), sys.exit() os._exit()...
从上一章了解各种K8s的特点,在这章将会教学如何安装Kind。 由於其利用docker的特性,会比使...
清理方法(The sanitization method),清除(purge),将使数据恢复不可行,...
前言 昨天文章有提到在 Tooltips 看到有趣的范例, 有用到 useEffect, 不过我有将...