在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请求传播。 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
模板:
FETCH
下面是 static/index.js
的内容:
const button = document.getElementsByTagName(“button”)[0];
button.addEventListener(“click”, function() {
getACookie();
});
function getACookie() {
fetch(“/get-cookie/”)
.then(response => {
// make sure to check response.ok in the real world!
return response.text();
})
.then(text => console.log(text));
}
当访问http://127.0.0.1:5000/
时,我们会看到一个按钮。 通过单击按钮,我们向/get-cookie/
发出获取请求并获取Cookie。 正如预期的那样,cookie 落在浏览器的 Cookie storage中。
对 Flask 应用程序进行一些更改,多加一个路由:
from flask import Flask, make_response, request, render_template, jsonify
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
@app.route(“/api/cities/”, methods=[“GET”])
def cities():
if request.cookies[“id”] == “3db4adj3d”:
cities = [{“name”: “Rome”, “id”: 1}, {“name”: “Siena”, “id”: 2}]
return jsonify(cities)
return jsonify(msg=“Ops!”)
另外,调整一下 JS 代码,用于下请求刚新增的路由:
const button = document.getElementsByTagName(“button”)[0];
button.addEventListener(“click”, function() {
getACookie().then(() => getData());
});
function getACookie() {
return fetch(“/get-cookie/”).then(response => {
// make sure to check response.ok in the real world!
return Promise.resolve(“All good, fetch the data”);
});
}
function getData() {
fetch(“/api/cities/”)
.then(response => {
// make sure to check response.ok in the real world!
return response.json();
})
.then(json => console.log(json));
当访问http://127.0.0.1:5000/
时,我们会看到一个按钮。 通过单击按钮,我们向/get-cookie/
发出获取请求以获取Cookie。 Cookie出现后,我们就会对/api/cities/
再次发出Fetch请求。
在浏览器的控制台中,可以看到请求回来 的数据。另外,在开发者工具的Network
选项卡中,可以看到一个名为Cookie的头,这是通过AJAX请求传给后端。
只要前端与后端在同一上下文中,在前端和后端之间来回交换cookie就可以正常工作:我们说它们来自同一源。
这是因为默认情况下,Fetch 仅在请求到达触发请求的来源时才发送凭据,即 Cookie
。
考虑另一种情况,在后端独立运行,可以这样启动应用程序:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
现在,在 Flask 应用程序之外的其他文件夹中,创建index.html
:
FETCH
使用以下代码在同一文件夹中创建一个名为index.js
的 JS 文件:
button.addEventListener(“click”, function() {
getACookie().then(() => getData());
});
function getACookie() {
return fetch(“http://localhost:5000/get-cookie/”).then(response => {
// make sure to check response.ok in the real world!
return Promise.resolve(“All good, fetch the data”);
});
}
function getData() {
fetch(“http://localhost:5000/api/cities/”)
.then(response => {
// make sure to check response.ok in the real world!
return response.json();
})
.then(json => console.log(json));
}
在同一文件夹中,从终端运行:
npx serve
此命令为您提供了要连接的本地地址/端口
,例如http://localhost:42091/
。 访问页面并尝试在浏览器控制台打开的情况下单击按钮。 在控制台中,可以看到:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/get-cookie/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
因为 http://localhost:5000/
与http://localhost:42091/.
不同。 它们是不同的域,因此会 CORS
的限制。
CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨域的服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与普通的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信。
默认情况下,除非服务器设置了Access-Control-Allow-Origin
的特定HTTP标头,否则浏览器将阻止AJAX对非相同来源的远程资源的请求。
要解决此第一个错误,我们需要为Flask配置CORS:
pip install flask-cors
然后将 CORS 应用于 Flask:
from flask import Flask, make_response, request, render_template, jsonify
from flask_cors import CORS
app = Flask(name)
CORS(app=app)
@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
@app.route(“/api/cities/”, methods=[“GET”])
def cities():
if request.cookies[“id”] == “3db4adj3d”:
cities = [{“name”: “Rome”, “id”: 1}, {“name”: “Siena”, “id”: 2}]
return jsonify(cities)
return jsonify(msg=“Ops!”)
现在尝试在浏览器控制台打开的情况下再次单击按钮。在控制台中你应该看到
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/api/cities/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
尽管我们犯了同样的错误,但这次的罪魁祸首是第二个路由。
你可以通过查看 “Network” 标签中的请求来确认,没有发送此类Cookie:
为了在不同来源的Fetch请求中包含cookie,我们必须提credentials
标志(默认情况下,它是相同来源)。
如果没有这个标志,Fetch 就会忽略 cookie,可以这样修复:
const button = document.getElementsByTagName(“button”)[0];
button.addEventListener(“click”, function() {
getACookie().then(() => getData());
});
function getACookie() {
return fetch(“http://localhost:5000/get-cookie/”, {
credentials: “include”
}).then(response => {
// make sure to check response.ok in the real world!
return Promise.resolve(“All good, fetch the data”);
});
}
function getData() {
fetch(“http://localhost:5000/api/cities/”, {
credentials: “include”
})
.then(response => {
// make sure to check response.ok in the real world!
return response.json();
})
.then(json => console.log(json));
}
credentials: "include"
必须在第一个 Fetch 请求中出现,才能将Cookie保存在浏览器的Cookie storage 中:
fetch(“http://localhost:5000/get-cookie/”, {
credentials: “include”
})
它还必须在第二个请求时出现,以允许将cookie传输回后端
fetch(“http://localhost:5000/api/cities/”, {
credentials: “include”
})
再试一次,我们还需要在后端修复另一个错误:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/get-cookie/. (Reason: expected ‘true’ in CORS header ‘Access-Control-Allow-Credentials’).
为了允许在CORS请求中传输cookie,后端还需要设置 Access-Control-Allow-Credentials
标头。
CORS(app=app, supports_credentials=True)
要点:为了使Cookie在不同来源之间通过AJAX请求传递,可以这样做:
-
credentials: “include” 用于前端的 fetch 请求中
-
Access-Control-Allow-Credentials
和Access-Control-Allow-Origin
用于后端
cookie可以通过AJAX请求传递,但是它们必须遵守我们前面描述的域规则。
Secure 属性是说如果一个 cookie 被设置了Secure=true
,那么这个cookie只能用https协议发送给服务器,用 http 协议是不发送的。换句话说,cookie 是在https
的情况下创建的,而且他的Secure=true,那么之后你一直用https访问其他的页面(比如登录之后点击其他子页面),cookie会被发送到服务器,你无需重新登录就可以跳转到其他页面。但是如果这是你把url改成http协议访问其他页面,你就需要重新登录了,因为这个cookie不能在http协议中发送。
可以这样设置 Secure 属性
response.set_cookie(key=“id”, value=“3db4adj3d”, secure=True)
如果要在真实环境中尝试,请可以运行以下命令,并注意curl
在此处是不通过HTTP
保存cookie:
curl -I http://serene-bastion-01422.herokuapp.com/get-secure-cookie/ --cookie-jar -
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
最后
基础知识是前端一面必问的,如果你在基础知识这一块翻车了,就算你框架玩的再6,webpack、git、node学习的再好也无济于事,因为对方就不会再给你展示的机会,千万不要因为基础错过了自己心怡的公司。前端的基础知识杂且多,并不是理解就ok了,有些是真的要去记。当然了我们是牛x的前端工程师,每天像背英语单词一样去背知识点就没必要了,只要平时工作中多注意总结,面试前端刷下题目就可以了。
tion-01422.herokuapp.com/get-secure-cookie/ --cookie-jar -
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-WzE3fRd5-1711856077305)]
[外链图片转存中…(img-dn7AQ2H7-1711856077306)]
[外链图片转存中…(img-ZOk1jbQI-1711856077306)]
[外链图片转存中…(img-DuM966EA-1711856077306)]
[外链图片转存中…(img-fJyGSevo-1711856077307)]
[外链图片转存中…(img-J3P1jM5V-1711856077307)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-fcGLPtzq-1711856077307)]
最后
基础知识是前端一面必问的,如果你在基础知识这一块翻车了,就算你框架玩的再6,webpack、git、node学习的再好也无济于事,因为对方就不会再给你展示的机会,千万不要因为基础错过了自己心怡的公司。前端的基础知识杂且多,并不是理解就ok了,有些是真的要去记。当然了我们是牛x的前端工程师,每天像背英语单词一样去背知识点就没必要了,只要平时工作中多注意总结,面试前端刷下题目就可以了。