- cookie是服务端返回数据的时候通过
Set-Cookie
的Header设置到浏览器上的内容 - 浏览器在保存了cookie之后,在下一次同源(协议,域名,端口三者一致)请求的时候,自动带上
- 结合服务端的session以此实现用户访问和权限验证
- cookie是键值对,可以设置多个值
- cookie的属性
- max-age和expires来控制设置过期的时间
- Secure只在https的时候才会携带和发送
- 设置HttpOnly就无法通过document.cookie来访问了
- 只能由服务端来读取,保证了安全性
- 如csrf攻击, 在网页中注入脚本或通过url来引导用户给攻击者服务器发送用户信息
- 攻击者可拿到用户登录状态,利用cookie来访问用户在服务器的数据
- 禁止重要数据通过js来访问是保证安全非常重要的一步
程序示例
-
test.html
<script> console.log(document.cookie); </script>
-
server.js
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { console.log('req come: ', req.url); if(req.url === '/') { const html = fs.readFileSync('test.html', 'utf8'); // 默认是下面这个writeHead设置,不写也可以 res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': 'uid=joh' }); res.end(html); } }).listen(8000, () => { console.log('server is running on port 8000'); });
-
启动程序:$
node server.js
-
打开控制台, 查看Network, 可以看到响应头上有了
Set-Cookie
字段 -
查看Application中的Cookie缓存, 发现已经被写入了
-
同时可以看到Console中已经打印出来了当前的cookie信息:uid=joh
-
再次刷新浏览器,可以看到在请求头上带上了当前的cookie,如果携带多个cookie, 用分号
;
进行区分 -
让cookie设置多个值,可以这样
res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': ['uid=joh', 'age=10'] // 不同的语言,设置方法不同,这里注意一下 });
-
重启服务,通过浏览器检查请求头,可以看到
Set-Cookie: uid=joh Set-Cookie: age=10
-
可见,设置了两次cookie信息, 同样, 浏览器缓存中cookie也被存入了这两个
-
cookie是可以设置时效的
- 一般没有设置过期时间,浏览器关闭后就没有了
- 设置
'Set-Cookie': ['uid=joh;max-age=1', 'age=10']
- 这样设置uid只有1s的有效期,过了1s再次刷新浏览器发现请求头上只有age的cookie
- 没有了uid的信息,因为1s时间很短, 这时已经过期了
- 同样的,除了用max-age,还可以用expires,两者用法不同
- max-age是设置多长时间,而expires是在什么时间点过期
- 所以max-age相对简单一些,expires要计算出那个时间点的时间
- 两者效果一样
-
关于cookie的HttpOnly属性
- 设置
'Set-Cookie': ['uid=joh;max-age=1', 'age=10; HttpOnly']
- 重启服务后刷新,可见Console中只打印了uid=joh, 是没有age=10的
- HttpOnly会禁止js访问cookie, 服务端可正常读取
- 设置
-
关于cookie的域名domain设置
- 设置访问域,一般来说当前域写了cookie, 其他域是无法访问的
- 举例: a.com写了cookie, 在b.com中是无法访问这个cookie
- 对同一个域名,cookie有其限制方案,如二级域名
const host = req.headers.host; // 在a.test.com下写cookie if(host === 'a.test.com') { const html = fs.readFileSync('test.html', 'utf8'); res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': ['uid=joh', 'age=10'] }); res.end(html); }
- 此时,在a.test.com中可以看到写入了cookie, 但是在b.test.com中无法看到任何相关cookie
- 也就是说我们不能跨域设置cookie, 不能同级或跨级设置,例如:
const host = req.headers.host; // 在a.test.com下写cookie if(host === 'a.test.com') { const html = fs.readFileSync('test.html', 'utf8'); res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': ['uid=joh', 'age=10; domain=test.com'] }); res.end(html); }
- 上面这个例子是不可以的,无法生效!但是我们可以从高级向低级设置cookie
- 例如:如果我们想在一级域名test.com中设置cookie, 让二级域名a.test.com来访问则是可以了
const host = req.headers.host; // 在a.test.com下写cookie if(host === 'test.com') { const html = fs.readFileSync('test.html', 'utf8'); res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': ['uid=joh', 'age=10; domain=test.com'] }); res.end(html); }
- 这样在test.com中查看Cookies, 可以看到设置了cookie, 其Domain是
.test.com
,其任何二级域名都可以共享cookie - 这样的设置,在a.test.com是能够访问到test.com中的cookie的,而且不会被写入任何cookie信息
- 这就是在二级域名下共享cookie信息,当然也有其他方式来做, 这是最简单的一种方式
- 小扩展:在Chrome浏览器下可以使用HostAdmin App应用工具来映射域名
-
关于session的应用
- cookie与session是两码事,不能混为一谈
- session有很多种实现方法,不一定会用到cookie
- 在网站开发中,用到最多的是用cookie来保存session
- 用户登录后把用户id或其对应的session的key来存入cookie里面
- 一般会把用户id加密转换成一个key
- 对应关系会存储在数据库或其他缓存中
- 下次用户请求后,服务端读取cookie里对应的key值
- 通过这个key定位用户信息,以此来获得一些操作的权限
- 用户登录后把用户id或其对应的session的key来存入cookie里面
- 其实session的应用不一定用cookie来实现,可以通过js写入请求头中也可以实现,缓存的话可以使用其他形式存储