作者:valentinog 译者:前端小智 来源:valentinog
点赞再看,微信搜索 【大迁世界】 关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHub
https://github.com/qq449245884/xiaozhi 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
Web 开发中的 cookie 是什么?cookie 是后端可以存储在用户浏览器中的小块数据。 Cookie 最常见用例包括用户跟踪,个性化以及身份验证。
Cookies 具有很多隐私问题,多年来一直受到严格的监管。
在本文中,主要侧重于技术方面:学习如何在前端和后端创建,使用 HTTP cookie。
后端配置后端示例是Flask编写的。如果你想跟着学习,可以创建一个新的Python虚拟环境,移动到其中并安装Flask
mkdir cookies && cd $_
python3 -m venv venv
source venv/bin/activate
pip install Flask
在项目文件夹中创建一个名为flask app.py
的新文件,并使用本文的示例在本地进行实验。
首先,cookies 从何而来? 谁创建 cookies ?
虽然可以使用document.cookie
在浏览器中创建 cookie,但大多数情况下,后端的责任是在将响应客户端请求之前在请求中设置 cookie。
后端是指可以通过以下方式创建 Cookie:
-
后端实际应用程序的代码(Python、JavaScript、PHP、Java)
-
响应请求的Web服务器(Nginx,Apache)
后端可以在 HTTP 请求求中 Set-Cookie 属性来设置 cookie,它是由键/值对以及可选属性组成的相应字符串:
Set-Cookie: myfirstcookie=somecookievalue
什么时候需要创建 cookie? 这取决于需求。
cookie 是简单的字符串。在项目文件夹中创建一个名为flask_app.py
的Python文件,并输入以下内容:
from flask import Flask, make_response
app = Flask(__name__)
@app.route("/index/", methods=["GET"])
def index():
response = make_response("Here, take some cookie!")
response.headers["Set-Cookie"] = "myfirstcookie=somecookievalue"
return response
然后运行应用程序:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
当该应用程序运行时,用户访问http://127.0.0.1:5000/index/
,后端将设置一个具有键/值对的名为Set-Cookie
的响应标头。
(127.0.0.1:5000
是开发中的 Flask 应用程序的默认侦听地址/端口)。
Set-Cookie
标头是了解如何创建cookie的关键:
response.headers["Set-Cookie"] = "myfirstcookie=somecookievalue"
大多数框架都有自己设置 cookie 的方法,比如Flask的set_cookie()
。
访问http://127.0.0.1:5000/index/
后,后端将在浏览器中设置cookie。 要查看此cookie,可以从浏览器的控制台调用document.cookie
:
或者可以在开发人员工具中选中Storage
选项卡。单击cookie,会看到 cookie 具体的内容:
在命令行上,还可以使用curl
查看后端设置了哪些 cookie
curl -I http://127.0.0.1:5000/index/
可以将 Cookie 保存到文件中以供以后使用:
curl -I http://127.0.0.1:5000/index/ --cookie-jar mycookies
在 stdout 上显示 cookie:
curl -I http://127.0.0.1:5000/index/ --cookie-jar -
请注意,没有HttpOnly
属性的cookie
,在浏览器中可以使用document.cookie
上访问,如果设置了 HttpOnly
属性,document.cookie
就读取不到。
Set-Cookie: myfirstcookie=somecookievalue; HttpOnly
现在,该cookie 仍将出现在 Storage
选项卡中,但是 document.cookie
返回的是一个空字符串。
从现在开始,为方便起见,使用Flask的 response.set_cookie()
在后端上创建 cookie。
你的浏览器得到一个 cookie。现在怎么办呢?一旦有了 cookie,浏览器就可以将cookie发送回后端。
这有许多用途发如:用户跟踪、个性化,以及最重要的身份验证。
例如,一旦你登录网站,后端就会给你一个cookie:
Set-Cookie: userid=sup3r4n0m-us3r-1d3nt1f13r
为了在每个后续请求中正确识别 我们的身份,后端会检查来自请求中浏览器的 cookie
要发送Cookie,浏览器会在请求中附加一个Cookie
标头:
Cookie: userid=sup3r4n0m-us3r-1d3nt1f13r
cookie 可以设置过期时间: Max-Age 和 expires
默认情况下,cookie 在用户关闭会话时即关闭浏览器时过期。要持久化cookie,我们可以通过expires
或Max-Age
属性
Set-Cookie: myfirstcookie=somecookievalue; expires=Tue, 09 Jun 2020 15:46:52 GMT; Max-Age=1209600
注意:Max-Age优先于expires。
cookie的作用域是网站路径: path 属性考虑该后端,该后端在访问http://127.0.0.1:5000/
时为其前端设置了一个新的 cookie。 相反,在其他两条路径上,我们打印请求的cookie
:
from flask import Flask, make_response, request
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
response = make_response("Here, take some cookie!")
response.set_cookie(key="id", value="3db4adj3d", path="/about/")
return response
@app.route("/about/", methods=["GET"])
def about():
print(request.cookies)
return "Hello world!"
@app.route("/contact/", methods=["GET"])
def contact():
print(request.cookies)
return "Hello world!"
运行该应用程序:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
在另一个终端中,如果我们与根路由建立连接,则可以在Set-Cookie
中看到cookie:
curl -I http://127.0.0.1:5000/ --cookie-jar cookies
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 23
Set-Cookie: id=3db4adj3d; Path=/about/
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 27 May 2020 09:21:37 GMT
请注意,此时 cookie 具有Path
属性:
Set-Cookie: id=3db4adj3d; Path=/about/
/about/
路由并保存 cookit
curl -I http://127.0.0.1:5000/about/ --cookie cookies
在 Flask 应用程序的终端中运行如下命令,可以看到:
ImmutableMultiDict([('id', '3db4adj3d')])
127.0.0.1 - - [27/May/2020 11:27:55] "HEAD /about/ HTTP/1.1" 200 -
正如预期的那样,cookie 返回到后端。 现在尝试访问 /contact/
路由:
url -I http://127.0.0.1:5000/contact/ --cookie cookies
在 Flask 应用程序的终端中运行如下命令,可以看到:
ImmutableMultiDict([])
127.0.0.1 - - [27/May/2020 11:29:00] "HEAD /contact/ HTTP/1.1" 200 -
这说明啥?cookie 的作用域是Path
。具有给定路径属性的cookie不能被发送到另一个不相关的路径,即使这两个路径位于同一域中。
这是cookie权限的第一层。
在cookie创建过程中省略Path
时,浏览器默认为/
。
cookie 的 Domain
属性的值控制浏览器是否应该接受cookie以及cookie返回的位置。
让我们看一些例子。
主机不匹配(错误的主机)查看 https://serene-bastion-01422.herokuapp.com/get-wrong-domain-cookie/
设置的cookie:
Set-Cookie: coookiename=wr0ng-d0m41n-c00k13; Domain=api.valentinog.com
这里的 cookie 来自serene-bastion-01422.herokuapp.com,但是Domain
属性具有api.valentinog.com。
浏览器没有其他选择来拒绝这个 cookie。比如 Chrome 会给出一个警告(Firefox没有)
查看 https://serene-bastion-01422.herokuapp.com/get-wrong-subdomain-cookie/
设置的cookie:
Set-Cookie: coookiename=wr0ng-subd0m41n-c00k13; Domain=secure-brushlands-44802.herokuapp.com
这里的 Cookie 来自serene-bastion-01422.herokuapp.com
,但**“Domain”**属性是secure-brushlands-44802.herokuapp.com
。
它们在相同的域上,但是子域名不同。 同样,浏览器也拒绝此cookie:
查看 https://www.valentinog.com/get-domain-cookie.html
设置的cookie:
set-cookie: cookiename=d0m41n-c00k13; Domain=valentinog.com
此cookie是使用 Nginx add_header在Web服务器上设置的:
add_header Set-Cookie "cookiename=d0m41n-c00k13; Domain=valentinog.com";
这里使用 Nginx 中设置cookie的多种方法。 Cookie 是由 Web 服务器或应用程序的代码设置的,对于浏览器来说无关紧要。
重要的是 cookie 来自哪个域。
在此浏览器将愉快地接受cookie,因为Domain
中的主机包括cookie所来自的主机。
换句话说,valentinog.com
包括子域名www.valentinog.com
。
同时,对valentinog.com
的新请求,cookie 都会携带着,以及任何对valentinog.com
子域名的请求。
这是一个附加了Cookie的 www
子域请求:
下面是对另一个自动附加cookie的子域的请求
查看 https://serene-bastion-01422.herokuapp.com/get-domain-cookie/:
设置的 cookie:
Set-Cookie: coookiename=d0m41n-c00k13; Domain=herokuapp.com
这里的 cookie 来自serene-bas-01422.herokuapp.com
,Domain
属性是herokuapp.com
。浏览器在这里应该做什么
你可能认为serene-base-01422.herokuapp.com
包含在herokuapp.com
域中,因此浏览器应该接受cookie。
相反,它拒绝 cookie,因为它来自公共后缀列表中包含的域。
Public Suffix List(公共后缀列表)。此列表列举了顶级域名和开放注册的域名。浏览器禁止此列表上的域名被子域名写入Cookie。
主机匹配(子域)查看 https://serene-bastion-01422.herokuapp.com/get-subdomain-cookie/:
设置的 cookie:
Set-Cookie: coookiename=subd0m41n-c00k13
当域在cookie创建期间被省略时,浏览器会默认在地址栏中显示原始主机,在这种情况下,我的代码会这样做:
response.set_cookie(key="coookiename", value="subd0m41n-c00k13")
当 Cookie 进入浏览器的 Cookie 存储区时,我们看到已应用Domain
:
现在,我们有来自serene-bastion-01422.herokuapp.com
的 cookie, 那 cookie 现在应该送到哪里?
如果你访问https://serene-bastion-01422.herokuapp.com/
,则 cookie 随请求一起出现:
但是,如果访问herokuapp.com
,则 cookie 不会随请求一起出现:
概括地说,浏览器使用以下启发式规则来决定如何处理cookies(这里的发送者主机指的是你访问的实际网址):
-
如果“Domain”中的域或子域与访问的主机不匹配,则完全拒绝 Cookie
-
如果
Domain
的值包含在公共后缀列表中,则拒绝 cookie -
如果
Domain
中的域或子域与访问在主机匹配,则接受 Cookie
一旦浏览器接受了cookie,并且即将发出请求,它就会说:
-
如果请求主机与我在
Domain
中看到的值完全匹配,刚会回传 cookie -
如果请求主机是与我在“Domain”中看到的值完全匹配的子域,则将回传 cookie
-
如果请求主机是
sub.example.dev
之类的子域,包含在example.dev
之类的 Domain 中,则将回传 cookie -
如果请求主机是例如
example.dev
之类的主域,而 Domain 是sub.example.dev
之类,则不会回传cookie。
Domain 和 Path 属性一直是 cookie 权限的第二层。
Cookies可以通过AJAX请求传递Cookies 可以通过AJAX请求传播。 AJAX 请求是使用 JS (XMLHttpRequest或Fetch)进行的异步HTTP请求,用于获取数据并将其发送回后端。
考虑 Flask的另一个示例,其中有一个模板,该模板又会加载 JS 文件:
from flask import Flask, make_response, render_template
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
@app.route("/get-cookie/", methods=["GET"])
def get_cookie():
response = make_response("Here, take some cookie!")
response.set_cookie(key="id", value="3db4adj3d")
return response
以下是 templates/index.html
模板:
Title
FETCH
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?