learn.lianglianglee.com/专栏/透视HTTP协议/19 让我知道你是谁:HTTP的Cookie机制.md.html
2022-05-11 19:04:14 +08:00

679 lines
27 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>19 让我知道你是谁HTTP的Cookie机制.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/透视HTTP协议/00 开篇词To Be a HTTP Hero.md.html">00 开篇词To Be a HTTP Hero.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/01 时势与英雄HTTP的前世今生.md.html">01 时势与英雄HTTP的前世今生.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/02 HTTP是什么HTTP又不是什么.md.html">02 HTTP是什么HTTP又不是什么.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/03 HTTP世界全览与HTTP相关的各种概念.md.html">03 HTTP世界全览与HTTP相关的各种概念.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/04 HTTP世界全览与HTTP相关的各种协议.md.html">04 HTTP世界全览与HTTP相关的各种协议.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/05 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?.md.html">05 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/06 域名里有哪些门道?.md.html">06 域名里有哪些门道?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/07 自己动手搭建HTTP实验环境.md.html">07 自己动手搭建HTTP实验环境.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/08 键入网址再按下回车,后面究竟发生了什么?.md.html">08 键入网址再按下回车,后面究竟发生了什么?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/09 HTTP报文是什么样子的.md.html">09 HTTP报文是什么样子的.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/10 应该如何理解请求方法?.md.html">10 应该如何理解请求方法?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/11 你能写出正确的网址吗?.md.html">11 你能写出正确的网址吗?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/12 响应状态码该怎么用?.md.html">12 响应状态码该怎么用?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/13 HTTP有哪些特点.md.html">13 HTTP有哪些特点.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/14 HTTP有哪些优点又有哪些缺点.md.html">14 HTTP有哪些优点又有哪些缺点.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/15 海纳百川HTTP的实体数据.md.html">15 海纳百川HTTP的实体数据.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/16 把大象装进冰箱HTTP传输大文件的方法.md.html">16 把大象装进冰箱HTTP传输大文件的方法.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/17 排队也要讲效率HTTP的连接管理.md.html">17 排队也要讲效率HTTP的连接管理.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/18 四通八达HTTP的重定向和跳转.md.html">18 四通八达HTTP的重定向和跳转.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/透视HTTP协议/19 让我知道你是谁HTTP的Cookie机制.md.html">19 让我知道你是谁HTTP的Cookie机制.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/20 生鲜速递HTTP的缓存控制.md.html">20 生鲜速递HTTP的缓存控制.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/21 良心中间商HTTP的代理服务.md.html">21 良心中间商HTTP的代理服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/22 冷链周转HTTP的缓存代理.md.html">22 冷链周转HTTP的缓存代理.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/23 HTTPS是什么SSLTLS又是什么.md.html">23 HTTPS是什么SSLTLS又是什么.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/24 固若金汤的根本(上):对称加密与非对称加密.md.html">24 固若金汤的根本(上):对称加密与非对称加密.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/25 固若金汤的根本(下):数字签名与证书.md.html">25 固若金汤的根本(下):数字签名与证书.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/26 信任始于握手TLS1.2连接过程解析.md.html">26 信任始于握手TLS1.2连接过程解析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/27 更好更快的握手TLS1.3特性解析.md.html">27 更好更快的握手TLS1.3特性解析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/28 连接太慢该怎么办HTTPS的优化.md.html">28 连接太慢该怎么办HTTPS的优化.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/29 我应该迁移到HTTPS吗.md.html">29 我应该迁移到HTTPS吗.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/30 时代之风HTTP2特性概览.md.html">30 时代之风HTTP2特性概览.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/31 时代之风HTTP2内核剖析.md.html">31 时代之风HTTP2内核剖析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/32 未来之路HTTP3展望.md.html">32 未来之路HTTP3展望.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/33 我应该迁移到HTTP2吗.md.html">33 我应该迁移到HTTP2吗.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/34 Nginx高性能的Web服务器.md.html">34 Nginx高性能的Web服务器.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/35 OpenResty更灵活的Web服务器.md.html">35 OpenResty更灵活的Web服务器.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/36 WAF保护我们的网络服务.md.html">36 WAF保护我们的网络服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/37 CDN加速我们的网络服务.md.html">37 CDN加速我们的网络服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/38 WebSocket沙盒里的TCP.md.html">38 WebSocket沙盒里的TCP.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/39 HTTP性能优化面面观.md.html">39 HTTP性能优化面面观.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/40 HTTP性能优化面面观.md.html">40 HTTP性能优化面面观.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/结束语 做兴趣使然的Hero.md.html">结束语 做兴趣使然的Hero.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>19 让我知道你是谁HTTP的Cookie机制</h1>
<p>在之前的第 13、14 讲中我曾经说过HTTP 是“无状态”的,这既是优点也是缺点。优点是服务器没有状态差异,可以很容易地组成集群,而缺点就是无法支持需要记录状态的事务操作。</p>
<p>好在 HTTP 协议是可扩展的,后来发明的 Cookie 技术,给 HTTP 增加了“记忆能力”。</p>
<h2>什么是 Cookie</h2>
<p>不知道你有没有看过克里斯托弗·诺兰导演的一部经典电影《记忆碎片》Memento里面的主角患有短期失忆症记不住最近发生的事情。</p>
<p><img src="assets/816df396bae0b37101543f967ff82125.jpeg" alt="" /></p>
<p>比如,电影里有个场景,某人刚跟主角说完话,大闹了一通,过了几分钟再回来,主角却是一脸茫然,完全不记得这个人是谁,刚才又做了什么,只能任人摆布。</p>
<p>这种情况就很像 HTTP 里“无状态”的 Web 服务器,只不过服务器的“失忆症”比他还要严重,连一分钟的记忆也保存不了,请求处理完立刻就忘得一干二净。即使这个请求会让服务器发生 500 的严重错误,下次来也会依旧“热情招待”。</p>
<p>如果 Web 服务器只是用来管理静态文件还好说,对方是谁并不重要,把文件从磁盘读出来发走就可以了。但随着 HTTP 应用领域的不断扩大,对“记忆能力”的需求也越来越强烈。比如网上论坛、电商购物,都需要“看客下菜”,只有记住用户的身份才能执行发帖子、下订单等一系列会话事务。</p>
<p>那该怎么样让原本无“记忆能力”的服务器拥有“记忆能力”呢?</p>
<p>看看电影里的主角是怎么做的吧。他通过纹身、贴纸条、立拍得等手段,在外界留下了各种记录,一旦失忆,只要看到这些提示信息,就能够在头脑中快速重建起之前的记忆,从而把因失忆而耽误的事情继续做下去。</p>
<p>HTTP 的 Cookie 机制也是一样的道理,既然服务器记不住,那就在外部想办法记住。相当于是服务器给每个客户端都贴上一张小纸条,上面写了一些只有服务器才能理解的数据,需要的时候客户端把这些信息发给服务器,服务器看到 Cookie就能够认出对方是谁了。</p>
<h2>Cookie 的工作过程</h2>
<p>那么Cookie 这张小纸条是怎么传递的呢?</p>
<p>这要用到两个字段:响应头字段<strong>Set-Cookie</strong>和请求头字段<strong>Cookie</strong></p>
<p>当用户通过浏览器第一次访问服务器的时候,服务器肯定是不知道他的身份的。所以,就要创建一个独特的身份标识数据,格式是“<strong>key=value</strong>”,然后放进 Set-Cookie 字段里,随着响应报文一同发给浏览器。</p>
<p>浏览器收到响应报文,看到里面有 Set-Cookie知道这是服务器给的身份标识于是就保存起来下次再请求的时候就自动把这个值放进 Cookie 字段里发给服务器。</p>
<p>因为第二次请求里面有了 Cookie 字段,服务器就知道这个用户不是新人,之前来过,就可以拿出 Cookie 里的值,识别出用户的身份,然后提供个性化的服务。</p>
<p>不过因为服务器的“记忆能力”实在是太差,一张小纸条经常不够用。所以,服务器有时会在响应头里添加多个 Set-Cookie存储多个“key=value”。但浏览器这边发送时不需要用多个 Cookie 字段,只要在一行里用“;”隔开就行。</p>
<p>我画了一张图来描述这个过程,你看过就能理解了。</p>
<p><img src="assets/9f6cca61802d65d063e24aa9ca7c38a4.png" alt="img" /></p>
<p>从这张图中我们也能够看到Cookie 是由浏览器负责存储的,而不是操作系统。所以,它是“浏览器绑定”的,只能在本浏览器内生效。</p>
<p>如果你换个浏览器或者换台电脑,新的浏览器里没有服务器对应的 Cookie就好像是脱掉了贴着纸条的衣服“健忘”的服务器也就认不出来了只能再走一遍 Set-Cookie 流程。</p>
<p>在实验环境里,你可以用 Chrome 访问 URI“/19-1”实地看一下 Cookie 工作过程。</p>
<p>首次访问时服务器会设置两个 Cookie。</p>
<p><img src="assets/974063541e5f9b43893db45ac4ce3687.png" alt="img" /></p>
<p>然后刷新这个页面,浏览器就会在请求头里自动送出 Cookie服务器就能认出你了。</p>
<p><img src="assets/da9b39d88ddd717a6e3feb6637dc3f9f.png" alt="img" /></p>
<p>如果换成 Firefox 等其他浏览器,因为 Cookie 是存在 Chrome 里的,所以服务器就又“蒙圈”了,不知道你是谁,就会给 Firefox 再贴上小纸条。</p>
<h2>Cookie 的属性</h2>
<p>说到这里你应该知道了Cookie 就是服务器委托浏览器存储在客户端里的一些数据而这些数据通常都会记录用户的关键识别信息。所以就需要在“key=value”外再用一些手段来保护防止外泄或窃取这些手段就是 Cookie 的属性。</p>
<p>下面这个截图是实验环境“/19-2”的响应头我来对着这个实际案例讲一下都有哪些常见的 Cookie 属性。</p>
<p><img src="assets/9dbb8b490714360475911ca04134df5d.png" alt="img" /></p>
<p>首先,我们应该<strong>设置 Cookie 的生存周期</strong>,也就是它的有效期,让它只能在一段时间内可用,就像是食品的“保鲜期”,一旦超过这个期限浏览器就认为是 Cookie 失效,在存储里删除,也不会发送给服务器。</p>
<p>Cookie 的有效期可以使用 Expires 和 Max-Age 两个属性来设置。</p>
<p><strong>Expires</strong>”俗称“过期时间”用的是绝对时间点可以理解为“截止日期”deadline。“<strong>Max-Age</strong>”用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age就可以得到失效的绝对时间。</p>
<p>Expires 和 Max-Age 可以同时出现,两者的失效时间可以一致,也可以不一致,但浏览器会优先采用 Max-Age 计算失效期。</p>
<p>比如在这个例子里Expires 标记的过期时间是“GMT 2019 年 6 月 7 号 8 点 19 分”,而 Max-Age 则只有 10 秒,如果现在是 6 月 6 号零点,那么 Cookie 的实际有效期就是“6 月 6 号零点过 10 秒”。</p>
<p>其次,我们需要<strong>设置 Cookie 的作用域</strong>,让浏览器仅发送给特定的服务器和 URI避免被其他网站盗用。</p>
<p>作用域的设置比较简单,“<strong>Domain</strong>”和“<strong>Path</strong>”指定了 Cookie 所属的域名和路径,浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。</p>
<p>使用这两个属性可以为不同的域名和路径分别设置各自的 Cookie比如“/19-1”用一个 Cookie“/19-2”再用另外一个 Cookie两者互不干扰。不过现实中为了省事通常 Path 就用一个“/”或者直接省略,表示域名下的任意路径都允许使用 Cookie让服务器自己去挑。</p>
<p>最后要考虑的就是<strong>Cookie 的安全性</strong>了,尽量不要让服务器以外的人看到。</p>
<p>写过前端的同学一定知道,在 JS 脚本里可以用 document.cookie 来读写 Cookie 数据这就带来了安全隐患有可能会导致“跨站脚本”XSS攻击窃取数据。</p>
<p>属性“<strong>HttpOnly</strong>”会告诉浏览器,此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问,浏览器的 JS 引擎就会禁用 document.cookie 等一切相关的 API脚本攻击也就无从谈起了。</p>
<p>另一个属性“<strong>SameSite</strong>”可以防范“跨站请求伪造”XSRF攻击设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送而“SameSite=Lax”则略宽松一点允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。</p>
<p>还有一个属性叫“<strong>Secure</strong>”,表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。</p>
<p>Chrome 开发者工具是查看 Cookie 的有力工具在“Network-Cookies”里可以看到单个页面 Cookie 的各种属性另一个“Application”面板里则能够方便地看到全站的所有 Cookie。</p>
<p><img src="assets/a8accc7e1836fa348c2fbd29f494069d.png" alt="img" /></p>
<p><img src="assets/37fbfef0490a20179c0ee274dccf5e6e.png" alt="img" /></p>
<h2>Cookie 的应用</h2>
<p>现在回到我们最开始的话题,有了 Cookie服务器就有了“记忆能力”能够保存“状态”那么应该如何使用 Cookie 呢?</p>
<p>Cookie 最基本的一个用途就是<strong>身份识别</strong>,保存用户的登录信息,实现会话事务。</p>
<p>比如,你用账号和密码登录某电商,登录成功后网站服务器就会发给浏览器一个 Cookie内容大概是“name=yourid”这样就成功地把身份标签贴在了你身上。</p>
<p>之后你在网站里随便访问哪件商品的页面,浏览器都会自动把身份 Cookie 发给服务器,所以服务器总会知道你的身份,一方面免去了重复登录的麻烦,另一方面也能够自动记录你的浏览记录和购物下单(在后台数据库或者也用 Cookie实现了“状态保持”。</p>
<p>Cookie 的另一个常见用途是<strong>广告跟踪</strong></p>
<p>你上网的时候肯定看过很多的广告图片,这些图片背后都是广告商网站(例如 Google它会“偷偷地”给你贴上 Cookie 小纸条,这样你上其他的网站,别的广告就能用 Cookie 读出你的身份,然后做行为分析,再推给你广告。</p>
<p>这种 Cookie 不是由访问的主站存储的,所以又叫“第三方 Cookie”third-party cookie。如果广告商势力很大广告到处都是那么就比较“恐怖”了无论你走到哪里它都会通过 Cookie 认出你来,实现广告“精准打击”。</p>
<p>为了防止滥用 Cookie 搜集用户隐私,互联网组织相继提出了 DNTDo Not Track和 P3PPlatform for Privacy Preferences Project但实际作用不大。</p>
<h2>小结</h2>
<p>今天我们学习了 HTTP 里的 Cookie 知识。虽然现在已经出现了多种 Local Web Storage 技术,能够比 Cookie 存储更多的数据,但 Cookie 仍然是最通用、兼容性最强的客户端数据存储手段。</p>
<p>简单小结一下今天的内容:</p>
<ol>
<li>Cookie 是服务器委托浏览器存储的一些数据,让服务器有了“记忆能力”;</li>
<li>响应报文使用 Set-Cookie 字段发送“key=value”形式的 Cookie 值;</li>
<li>请求报文里用 Cookie 字段发送多个 Cookie 值;</li>
<li>为了保护 Cookie还要给它设置有效期、作用域等属性常用的有 Max-Age、Expires、Domain、HttpOnly 等;</li>
<li>Cookie 最基本的用途是身份识别,实现有状态的会话事务。</li>
</ol>
<p>还要提醒你一点,因为 Cookie 并不属于 HTTP 标准RFC6265而不是 RFC2616/7230所以语法上与其他字段不太一致使用的分隔符是“;”,与 Accept 等字段的“,”不同,小心不要弄错了。</p>
<h2>课下作业</h2>
<ol>
<li>如果 Cookie 的 Max-Age 属性设置为 0会有什么效果呢</li>
<li>Cookie 的好处已经很清楚了,你觉得它有什么缺点呢?</li>
</ol>
<p>欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。</p>
<p><img src="assets/f03db082760cfa8920b266ce44f52597.png" alt="unpreview" /></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/透视HTTP协议/18 四通八达HTTP的重定向和跳转.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/透视HTTP协议/20 生鲜速递HTTP的缓存控制.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997d08cbbb3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>