learn.lianglianglee.com/专栏/透视HTTP协议/07 自己动手,搭建HTTP实验环境.md.html
2022-05-11 19:04:14 +08:00

717 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>07 自己动手搭建HTTP实验环境.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 class="current-tab" 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 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>07 自己动手搭建HTTP实验环境</h1>
<p>这一讲是“破冰篇”的最后一讲,我会先简单地回顾一下之前的内容,然后在 Windows 系统上实际操作,用几个应用软件搭建出一个“最小化”的 HTTP 实验环境,方便后续的“基础篇”“进阶篇”“安全篇”的学习。</p>
<h2>“破冰篇”回顾</h2>
<p>HTTP 协议诞生于 30 年前,设计之初的目的是用来传输纯文本数据。但由于形式灵活,搭配 URI、HTML 等技术能够把互联网上的资源都联系起来,构成一个复杂的超文本系统,让人们自由地获取信息,所以得到了迅猛发展。</p>
<p>HTTP 有多个版本,目前应用的最广泛的是 HTTP/1.1,它几乎可以说是整个互联网的基石。但 HTTP/1.1 的性能难以满足如今的高流量网站,于是又出现了 HTTP/2 和 HTTP/3。不过这两个新版本的协议还没有完全推广开。在可预见的将来HTTP/1.1 还会继续存在下去。</p>
<p>HTTP 翻译成中文是“超文本传输协议”,是一个应用层的协议,通常基于 TCP/IP能够在网络的任意两点之间传输文字、图片、音频、视频等数据。</p>
<p>HTTP 协议中的两个端点称为<strong>请求方</strong><strong>应答方</strong>。请求方通常就是 Web 浏览器,也叫 user agent应答方是 Web 服务器,存储着网络上的大部分静态或动态的资源。</p>
<p>在浏览器和服务器之间还有一些“中间人”的角色,如 CDN、网关、代理等它们也同样遵守 HTTP 协议,可以帮助用户更快速、更安全地获取资源。</p>
<p>HTTP 协议不是一个孤立的协议,需要下层很多其他协议的配合。最基本的是 TCP/IP实现寻址、路由和可靠的数据传输还有 DNS 协议实现对互联网上主机的定位查找。</p>
<p>对 HTTP 更准确的称呼是“<strong>HTTP over TCP/IP</strong>”,而另一个“<strong>HTTP over SSL/TLS</strong>”就是增加了安全功能的 HTTPS。</p>
<h2>软件介绍</h2>
<p>常言道“实践出真知”,又有俗语“光说不练是假把式”。要研究 HTTP 协议,最好有一个实际可操作、可验证的环境,通过实际的数据、现象来学习,肯定要比单纯的“动嘴皮子”效果要好的多。</p>
<p>现成的环境当然有,只要能用浏览器上网,就会有 HTTP 协议,就可以进行实验。但现实的网络环境又太复杂了,有很多无关的干扰因素,这些“噪音”会“淹没”真正有用的信息。</p>
<p>所以,我给你的建议是:搭建一个“<strong>最小化</strong>”的环境,在这个环境里仅有 HTTP 协议的两个端点:请求方和应答方,去除一切多余的环节,从而可以抓住重点,快速掌握 HTTP 的本质。</p>
<p><img src="assets/85cadf90dc96cf413afaf8668689ef0b.png" alt="img" /></p>
<p>简单说一下这个“最小化”环境用到的应用软件:</p>
<ul>
<li>Wireshark</li>
<li>Chrome/Firefox</li>
<li>Telnet</li>
<li>OpenResty</li>
</ul>
<p><strong>Wireshark</strong>是著名的网络抓包工具,能够截获在 TCP/IP 协议栈中传输的所有流量,并按协议类型、地址、端口等任意过滤,功能非常强大,是学习网络协议的必备工具。</p>
<p>它就像是网络世界里的一台“高速摄像机”,把只在一瞬间发生的网络传输过程如实地“拍摄”下来,事后再“慢速回放”,让我们能够静下心来仔细地分析那一瞬到底发生了什么。</p>
<p><strong>Chrome</strong>是 Google 开发的浏览器,是目前的主流浏览器之一。它不仅上网方便,也是一个很好的调试器,对 HTTP/1.1、HTTPS、HTTP/2、QUIC 等的协议都支持得非常好,用 F12 打开“开发者工具”还可以非常详细地观测 HTTP 传输全过程的各种数据。</p>
<p>如果你更习惯使用<strong>Firefox</strong>,那也没问题,其实它和 Chrome 功能上都差不太多,选择自己喜欢的就好。</p>
<p>与 Wireshark 不同Chrome 和 Firefox 属于“事后诸葛亮”,不能观测 HTTP 传输的过程,只能看到结果。</p>
<p><strong>Telnet</strong>是一个经典的虚拟终端,基于 TCP 协议远程登录主机,我们可以使用它来模拟浏览器的行为,连接服务器后手动发送 HTTP 请求,把浏览器的干扰也彻底排除,能够从最原始的层面去研究 HTTP 协议。</p>
<p><strong>OpenResty</strong>你可能比较陌生,它是基于 Nginx 的一个“强化包”,里面除了 Nginx 还有一大堆有用的功能模块,不仅支持 HTTP/HTTPS还特别集成了脚本语言 Lua 简化 Nginx 二次开发,方便快速地搭建动态网关,更能够当成应用容器来编写业务逻辑。</p>
<p>选择 OpenResty 而不直接用 Nginx 的原因是它相当于 Nginx 的“超集”,功能更丰富,安装部署更方便。我也会用 Lua 编写一些服务端脚本,实现简单的 Web 服务器响应逻辑,方便实验。</p>
<h2>安装过程</h2>
<p>这个“最小化”环境的安装过程也比较简单,大约只需要你半个小时不到的时间就能搭建完成。</p>
<p>我在 GitHub 上为本专栏开了一个项目:<a href="https://github.com/chronolaw/http_study.git">http_study</a>可以直接用“git clone”下载或者去 Release 页面,下载打好的<a href="https://github.com/chronolaw/http_study/releases">压缩包</a></p>
<p>我使用的操作环境是 Windows 10如果你用的是 Mac 或者 Linux可以用 VirtualBox 等虚拟机软件安装一个 Windows 虚拟机,再在里面操作。</p>
<p>首先你要获取<strong>最新</strong>的 http_study 项目源码,假设 clone 或解压的目录是“D:\http_study”操作完成后大概是下图这个样子。</p>
<p><img src="assets/862511b8ef87f78218631d832927bcee.png" alt="img" /></p>
<p>Chrome 和 WireShark 的安装比较简单一路按“下一步”就可以了。版本方面使用最新的就好我的版本可能不是最新的Chrome 是 73WireShark 是 3.0.0。</p>
<p>Windows 10 自带 Telnet不需要安装但默认是不启用的需要你稍微设置一下。</p>
<p>打开 Windows 的设置窗口搜索“Telnet”就会找到“启用或关闭 Windows 功能”在这个窗口里找到“Telnet 客户端”,打上对钩就可以了,可以参考截图。</p>
<p><img src="assets/1af035861c4fd33cb42005eaa1f5f247.png" alt="img" /></p>
<p>接下来我们要安装 OpenResty去它的<a href="https://openresty.org/">官网</a>点击左边栏的“Download”进入下载页面下载适合你系统的版本这里我下载的是 64 位的 1.15.8.1包的名字是“openresty-1.15.8.1-win64.zip”</p>
<p><img src="assets/ee7016fecd79919de550677af32f740a.png" alt="img" /></p>
<p>然后要注意,你必须把 OpenResty 的压缩包解压到刚才的“D:\http_study”目录里并改名为“openresty”。</p>
<p><img src="assets/5acb89c96041f91bbc747b7e909fd4b5.png" alt="img" /></p>
<p>安装工作马上就要完成了,为了能够让浏览器能够使用 DNS 域名访问我们的实验环境,还要改一下本机的 hosts 文件位置在“C:\WINDOWS\system32\drivers\etc”在里面添加三行本机 IP 地址到测试域名的映射,你也可以参考 GitHub 项目里的 hosts 文件,这就相当于在一台物理实机上“托管”了三个虚拟主机。</p>
<pre><code>127.0.0.1 www.chrono.com
127.0.0.1 www.metroid.net
127.0.0.1 origin.io
</code></pre>
<p>注意修改 hosts 文件需要管理员权限,直接用记事本编辑是不行的,可以切换管理员身份,或者改用其他高级编辑器,比如 Notepad++,而且改之前最好做个备份。</p>
<p>到这里,我们的安装工作就完成了!之后你就可以用 Wireshark、Chrome、Telnet 在这个环境里随意“折腾”,弄坏了也不要紧,只要把目录删除,再来一遍操作就能复原。</p>
<h2>测试验证</h2>
<p>实验环境搭建完了,但还需要把它运行起来,做一个简单的测试验证,看是否运转正常。</p>
<p>首先我们要启动 Web 服务器,也就是 OpenResty。</p>
<p>在 http_study 的“www”目录下有四个批处理文件分别是</p>
<p><img src="assets/e5d35bb94c46bfaaf8ce5c143b2bb2da.png" alt="img" /></p>
<ul>
<li>start启动 OpenResty 服务器;</li>
<li>stop停止 OpenResty 服务器;</li>
<li>reload重启 OpenResty 服务器;</li>
<li>list列出已经启动的 OpenResty 服务器进程。</li>
</ul>
<p>使用鼠标双击“start”批处理文件就会启动 OpenResty 服务器在后台运行,这个过程可能会有 Windows 防火墙的警告,选择“允许”即可。</p>
<p>运行后鼠标双击“list”可以查看 OpenResty 是否已经正常启动,应该会有两个 nginx.exe 的后台进程,大概是下图的样子。</p>
<p><img src="assets/dba34b8a38e98bef92289315db29ee1d.png" alt="img" /></p>
<p>有了 Web 服务器后,接下来我们要运行 Wireshark开始抓包。</p>
<p>因为我们的实验环境运行在本机的 127.0.0.1 上,也就是 loopback“环回”地址。所以在 Wireshark 里要选择“Npcap loopback Adapter”过滤器选择“HTTP TCP port(80)”,即只抓取 HTTP 相关的数据包。鼠标双击开始界面里的“Npcap loopback Adapter”即可开始抓取本机上的网络数据。</p>
<p><img src="assets/128d8a5ed9cdd666dbfa4e17fd39afc4.png" alt="img" /></p>
<p>然后我们打开 Chrome在地址栏输入“<a href="http://localhost/">http://localhost</a>/”,访问刚才启动的 OpenResty 服务器,就会看到一个简单的欢迎界面,如下图所示。</p>
<p><img src="assets/d7f12d4d480d7100cd9804d2b16b8a88.png" alt="img" /></p>
<p>这时再回头去看 Wireshark应该会显示已经抓到了一些数据就可以用鼠标点击工具栏里的“停止捕获”按钮告诉 Wireshark“到此为止”不再继续抓包。</p>
<p><img src="assets/f7d05a3939d81742f18d2da7a1883179.png" alt="img" /></p>
<p>至于这些数据是什么,表示什么含义,我会在下一讲再详细介绍。</p>
<p>如果你能够在自己的电脑上走到这一步就说明“最小化”的实验环境已经搭建成功了不要忘了实验结束后运行批处理“stop”停止 OpenResty 服务器。</p>
<h2>小结</h2>
<p>这次我们学习了如何在自己的电脑上搭建 HTTP 实验环境,在这里简单小结一下今天的内容。</p>
<ol>
<li>现实的网络环境太复杂,有很多干扰因素,搭建“最小化”的环境可以快速抓住重点,掌握 HTTP 的本质;</li>
<li>我们选择 Wireshark 作为抓包工具,捕获在 TCP/IP 协议栈中传输的所有流量;</li>
<li>我们选择 Chrome 或 Firefox 浏览器作为 HTTP 协议中的 user agent</li>
<li>我们选择 OpenResty 作为 Web 服务器,它是一个 Nginx 的“强化包”,功能非常丰富;</li>
<li>Telnet 是一个命令行工具,可用来登录主机模拟浏览器操作;</li>
<li>在 GitHub 上可以下载到本专栏的专用项目源码,只要把 OpenResty 解压到里面即可完成实验环境的搭建。</li>
</ol>
<h2>课下作业</h2>
<ol>
<li>
<p>按照今天所学的,在你自己的电脑上搭建出这个 HTTP 实验环境并测试验证。</p>
</li>
<li>
<p>由于篇幅所限,我无法详细介绍 Wireshark你有时间可以再上网搜索 Wireshark 相关的资料,了解更多的用法。</p>
</li>
</ol>
<p>欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。</p>
<p><img src="assets/03727c2a64cbc628ec18cf39a6a526dd.png" alt="unpreview" /></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/透视HTTP协议/06 域名里有哪些门道?.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/透视HTTP协议/08 键入网址再按下回车,后面究竟发生了什么?.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":"70997cebbeeb3cfa","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>