重新认识Cookie的限制

背景是在使用vue-cli3开发模式启动的服务,登录成功服务端返回了信息,并且设置了cookie,但是在IE11下却无法找到服务端设置的cookie信息,自己代码中添加的cookie反而成功了。又是潜在的坑?

vue-cli3使用development模式启动的配置

vue.config.js配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'api.com', // 开发环境
changeOrigin: true,
pathRewrite: {
'^/api': '/api',
},
cookieDomainRewrite: {
'api.com': 'localhost',
},
},
},
},
};

原因

原因就是Set-Cookie中的Domain=localhost的问题,因为规范规定domain必须是一个至少含有两个dot的,但是还不能是ip。其实呢,IE没错,错在自己不知道规范和套路。

解决方案

修改vue.config的配置,重定向给null, false, ‘’, 或者localhost.cn (etc/hosts文件里面配置下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'api.com', // 开发环境
changeOrigin: true,
pathRewrite: {
'^/api': '/api',
},
cookieDomainRewrite: {
'api.com': null, // '' 或 null 或 false都行
},
},
},
},
};

重新认识cookie的限制

虽然cookie浏览器都支持,但是还是有一堆的潜规则。

cookie的属性
cookie的属性

cookie属性值和属性名称编码

所有在 cookie 名称或 cookie 值中不允许的特殊字符都使用百分比编码对每个字符的 UTF-8 十六进制等效项进行编码。
Cookie 名称或 Cookie 值中允许并且仍然编码的唯一字符是百分比字符,它将转义以将百分比输入解释为文本。

IE下cookie的path不能包含文件名

http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx
Q8: Are there any limits to the HTML DOM document.cookie property?

由于基础 WinINET InternetGetCookie 实现中存在一个模糊的 bug,IE 的文档.cookie 如果使用包含文件名的路径属性设置,则不会返回 Cookie。

1
Set-Cookie: HTTPSet-PathCookie=PASS;path=/check.htm

这个cookie不会出现在document.cookie中,但是HTTP requests还是会附带上。

https://github.com/js-cookie/js-cookie/wiki/Frequently-Asked-Questions#why-are-my-cookies-being-deleted

它们可能太大,或者同一域中的 Cookie 太多。

根据RFC 6265,这是浏览器为 Cookie 实现的规范:

实际的用户代理实现对它们可以存储的 Cookie 的数量和大小有限制。通用用户代理应提供以下每个最低功能:

  • 每个 Cookie 至少 4096 字节(以 Cookie 的名称、值和属性的长度之和来衡量)。
  • 每个域最多 50 个 Cookie。
  • 总共最多3000个cookie。

不要超过 RFC 中规定的强制限制,这意味着浏览器可能会由于此大小限制而截断 Cookie。

https://github.com/js-cookie/js-cookie/issues/226

不可以,会有意想不到效果。

cookie不会被删除的情况

这个问题我真的遇到了,当时还很奇怪,又纠结了。

会话期Cookie

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies#%E4%BC%9A%E8%AF%9D%E6%9C%9FCookie
会话期Cookie是最简单的Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。会话期Cookie不需要指定过期时间(Expires)或者有效期(Max-Age)。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期Cookie也会被保留下来,就好像浏览器从来没有关闭一样。

注意 :如果你这样设置,会话期cookie也不会删除,所以前端一定要做好判断,这个坑我又踩了

Continue where you left off
Continue where you left off

持久性Cookie

和关闭浏览器便失效的会话期Cookie不同,持久性Cookie可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。

cookie的Secure和HttpOnly属性

标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。
从 Chrome 52 和 Firefox 52 开始,不安全的站点(http:)无法使用Cookie的 Secure 标记。
HttpOnly 标记的Cookie,只能在HTTP request headers里面,JavaScript不能获取。

判断当前页面是否启用cookie

navigator.cookieEnabled 返回一个布尔值,来表示当前页面是否启用了 cookie。本属性为只读属性。

如果所有现代浏览器默认SameSite=Strict,嘿嘿一堆应用会出问题。
别人的文章Chrome默认启用Cookie Samesite属性

cookie-samesite-attribute
cookie-samesite-attribute

微软你有毛病,IE11还区分Windows版本,SameSite功能部分支持。

总结

没想到普遍支持的cookie,还有如此多的限制,恨自己的经验不足。

参考

internet-explorer-11-wont-set-cookies-on-a-site

understanding-session-lifetime/

cookie_spec

cookies-on-localhost-with-explicit-domain

cookie-domain

MDN_HTTP_Access_control_CORS

阮一峰–跨域资源共享 CORS 详解

cors-tutorials

preflight-request

前端常见跨域方案

Spring mvc解决跨域请求:Response to preflight request doesn’t pass access control check

什么是浏览器跨域,如何解决跨域问题,什么是 CORS?从入门到精通

Chrome默认启用Cookie Samesite属性

node-http-proxy#options

HTTP Cookie and Set-Cookie header fields

js-cookie
Frequently-Asked-Questions#why-are-my-cookies-being-deleted
Internet Explorer Cookie Internals (FAQ)
Chrome doesn’t delete session cookies
【译】Cookie的SameSite属性