HTTP 协议
HTTP (全称为 "超文本传输协议") 是一种应用非常广泛的 应用层协议。所谓 "超文本" 的含义, 就是传输的内容不仅仅是文本(比如 html, css 这个就是文本), 还可以是一些 其他的资源, 比如图片, 视频, 音频等二进制的数据。浏览器获取到网页,就是基于 HTTP 的,也就相当于 浏览器 和 服务器 之间的桥梁。


目前我们主要使用的还是 HTTP1.1
HTTP 协议的工作过程
当我们在浏览器中输入一个 "网址", 此时浏览器就会给对应的服务器发送一个 HTTP 请求. 对方服务器收 到这个请求之后, 经过计算处理, 就会返回一个 HTTP 响应.

事实上, 当我们访问一个网站的时候, 可能涉及不止一次的 HTTP 请求/响应 的交互过程。可以通过 fiddler 来抓包显示,可以知道 HTTP 是一个 行文本 的协议。

Fiddler 相当于一个 "代理". 浏览器访问 sogou.com 时, 就会把 HTTP 请求先发给 Fiddler, Fiddler 再把请求转发给 sogou 的服务器. 当 sogou 服务器返回数据时, Fiddler 拿到返回数据, 再把数据交给浏览器. 因此 Fiddler 对于浏览器和 sogou 服务器之间交互的数据细节, 都是非常清楚的.(相当于是一个跑腿小弟)

HTTP 协议格式

HTTP 请求 (Request)
认识 URL
平时我们俗称的 "网址" 其实就是说的 URL (Uniform Resource Locator 统一资源定位符). 互联网上的每个文件都有一个唯一的URL。

URL 最关键的四个部分:1. 域名 / IP,2. 端口号,3. 带层次的路径,4. 查询字符串。

例如:https://v.bitedu.vip/personInf/student?userId=10000&classId=100
https : 协议方案名. 常见的有 http 和 https, 也有其他的类型. (例如访问 mysql 时用的 jdbc:mysql )
user:pass : 登陆信息. 现在的网站进行身份认证一般不再通过 URL 进行了. 一般都会省略
v.bitedu.vip : 服务器地址. 此处是一个 "域名", 域名会通过 DNS 系统解析成一个具体的 IP 地址.
端口号: 上面的 URL 中端口号被省略了. 当端口号省略的时候, 浏览器会根据协议类型自动决定使用 哪个端口. 例如 http 协议默认使用 80 端口, https 协议默认使用 443 端口.
/personInf/student : 带层次的文件路径.
userId=10000&classId=100 : 查询字符串(query string). 本质是一个键值对结构。以 ?开头,键值对之间使用 & 分隔,键和值之间使用 = 分隔。
片段标识: 此 URL 中省略了片段标识,片段标识主要用于页面内跳转, 通过不同的片段标识跳转到文档的不同章节。
关于 URL encode
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现. 比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

"+" 被转义成了 "%2B"
urldecode就是urlencode的逆过程,就是解码跟编码的过程。
方法
“天下的 HTTP 方法是 十斗,GET 独占八斗,POST 占一斗,剩下的方法分一斗”

1. GET 方法
常用于获取服务器上的某个资源 .
1. 在浏览器中直接输入 URL, 此时浏览器就会发送出一个 GET 请求 .
2. HTML 中的 link, img, script 等标签 , 也会触发 GET 请求 .
3. 使用 JavaScript 中的 ajax 也能构造 GET 请求.

GET 请求的特点:
1. 首行的第一部分为 GET
2. URL 的 query string 可以为空 , 也可以不为空 .
3. header 部分有若干个键值对结构 .
4. body 部分为空 .
2. POST 方法
多用于提交用户输入的数据给服务器 ( 例如登陆页面 ).
1. 通过 HTML 中的 form 标签可以构造 POST 请求
2. 或者使用 JavaScript 的 ajax 也可以构造 POST 请求 .

POST 请求的特点:
1. 首行的第一部分为 POST
2. URL 的 query string 一般为空 ( 也可以不为空 )
3. header 部分有若干个键值对结构 .
4. body 部分一般不为空 . body 内的数据格式通过 header 中的 Content - Type 指定 . body 的长度由 header 中的 Content - Length 指定 .
HTTP 请求可以分成四个部分:
1. 首行
2. 请求头(herder)
3. 空行
4. 正文(body)
如果是 GET 请求,则没有 body。如果是 POST 请求,一般都有 body。
GET 和 POST 的区别
首先没有本质上的区别,大部分场景彼此能相互替代,只是在使用习惯上有所差异。
1. GET 请求一般是用于从服务器获取数据;POST 一般是用于给服务器提交数据。
2. GET 也可以给服务器提交数据,GET 提交的数据一般是放在 query string 上的;POST 提交数据则是通过 body。
3. GET 通常会被设计成幂等(相同的输入,得到的结果是确定的);POST 则不要求幂等。
4. GET 可以被缓存(把请求结果保存下来,下次请求直接读取缓存结果);POST 一般则不能被缓存。
注意!
说 GET 请求传输的数据存在上限这个说法是不正确的!因为在 rfc 标准文档上并没有对 HTTP GET 请求的长度上线明确规定。只不过是以前条件欠佳,浏览器 / 服务器实现的时候搞了个限制而已。
POST 比 GET 更安全其实也不正确,虽然使用 GET 请求时在登陆的时候用户名和密码会通过 query string 来传递从而出现在浏览器地址栏中,但是安全的核心应该是加密后不易被破解,直接显示和不直接显示出来似乎有点牵强。
3. 其他方法
PUT 与 POST 相似,只是具有幂等特性,一般用于更新
DELETE 删除服务器指定资源
OPTIONS 返回服务器所支持的请求方法
HEAD 类似于 GET ,只不过响应体不返回,只返回响应头
TRACE 回显服务器端收到的请求,测试的时候会用到这个
CONNECT 预留,暂无使用
请求 "报头" (header)
header 的整体的格式也是 "键值对" 结构。每个键值对占一行. 键和值之间使用分号分割.
Host
表示服务器主机的地址和端口.

这里的 地址 和 端口 是用来描述最终要访问的目标,这里大多数情况下和 URL 中一样,除非用了代理服务器那么 URL 的地址就是代理服务器的。
Content-Length
表示 body 中的数据长度 .
Content-Type
表示请求的 body 中的数据格式 .

User-Agent (简称 UA)
表示浏览器 / 操作系统的属性。
在早期的浏览器中只支持文本,或者最多也就支持图片,后来又又了支持视频音频的。因此网站的开发就得根据这不同浏览器版本来确定显示哪个版本的页面。但是现在基本都是最新浏览器了,user agent 用处也少了,现在主要是用来区分 PC端 和 移动端。
Referer
表示这个页面是从哪个页面跳转过来的。如果是直接在浏览器中输入 URL, 或者直接通过收藏夹访问页面时是没有 Referer 的。
作用:例如广告商在各个搜索引擎都有投放广告,为了区分出是哪个从搜索引擎点击的就可以根据 referer 来确定。
Cookie
本质上是 浏览器 给 网页 提供的一种本地存储数据的机制,因为为了安全默认情况网页是不能访问计算机硬盘的。即是一种由服务器发送到客户端浏览器并保存在本地的小型文件。

cookie 是通过键值对的方式来组织数据的,其中这里面的内容是程序猿自定义的只有他自己知道是啥意思,里面也会包含着 cookie 的过期时间(越敏感的网站时间越短)。
cookie 中的数据来自于服务器。服务器会通过 HTTP 响应的 报头部分(Set-Cookie字段)来决定浏览器的 cookie 要存什么内容。
cookie 是存储在硬盘上的。不同的浏览器有着各自的 cookie,同一个浏览器下的不同域名也对应着不同的 cookie。
cookie 是要返回到服务器上的。当客户端访问浏览器的时候,就会自动把 cookie 的内容带入到请求中,服务器就会根据客户端的状态响应相关的内容。
我们可以把网站比作一个超市,而 cookie 就像是超市给顾客的积分卡。当你第一次去这个超市(访问网站)时,超市会给你一张积分卡(设置 cookie),上面可能记录了一些关于你的信息,比如你的会员编号等。然后当你下次再来这个超市(再次访问网站)时,你拿出这张积分卡(浏览器携带 cookie),超市就能通过积分卡知道你是老顾客,能获取到之前记录在积分卡上的信息,比如知道你之前买过什么东西呀之类的,然后可以根据这些信息给你提供更个性化的服务或展示。简单来说,cookie 就是网站存放在你浏览器里的一些小信息,用来帮助网站识别你和记住一些和你相关的事情。
认识请求 "正文" (body)
正文中的内容格式和 header 中的 Content-Type 密切相关 . 下面 三种常见的情况 可以通过抓包来观察这几种情况:
1) application/x-www-form-urlencoded
2) multipart/form-data
3) application/json
在 HTTP 协议中,程序猿能自定义的有:1. URL 中的路径、2. URL 中的 query string、3. header 中的键值对、4. header 中的 cookie 的键值对、5. body。
HTTP 响应详解
状态码 (status code)
状态码表示访问一个页面的结果. ( 是访问成功 , 还是失败 , 还是其他的一些情况)

常见状态码
200 OK
这是一个最常见的状态码, 表示访问成功。
301 Moved Permanently
永久重定向(就相当于手机号码中的 "呼叫转移" 功能 ). 当浏览器收到这种响应时 , 后续的请求都会被自动改成新的地址。 301 也是通过 Location 字段来表示要重定向到的新地址 .
302 Move temporarily
404 Not Found
访问的资源不存在,在服务器上没有找到资源。
403 Forbidden
表示访问被拒绝. 有的页面通常需要用户具有一定的权限才能访问 (比如 登陆后才能访问 )。
500 Internal Server Error
服务器出现内部错误. 一般是服务器的代码执行过程中遇到了一些特殊情况 ( 服务器异常崩溃 ) 会产生这个状态码. 平时常用的网站很少会出现 500。
504 Gateway Timeout
当服务器负载比较大的时候, 服务器处理单条请求的时候消耗的时间就会很长 , 就可能会导致出现超时的情况。
状态码小结

1**:等等,正在处理
2**:成功
3**:重定向
4**:客户端错误
5**:服务器错误
通过 form 表单构造 HTTP 请求
form (表单 ) 是 HTML 中的一个常用标签 . 可以用于给服务器发送 GET 或者 POST 请求 .
form 发送 GET 请求
form 的重要参数:
action: 构造的 HTTP 请求的 URL 是什么 .
method: 构造的 HTTP 请求的 方法 是 GET 还是 POST (form 只支持 GET 和 POST).
input 的重要参数:
type: 表示输入框的类型 . text 表示文本 , password 表示密码 , submit 表示提交按钮 .
name: 表示构造出的 HTTP 请求的 query string 的 key. query string 的 value 就是输入框的用户输入的内容.
value: input 标签的值 . 对于 type 为 submit 类型来说 , value 就对应了按钮上显示的文本 .
<form action="http://www.sogou.com" method="GET">
<input type="text" name="studentName">
<input type="submit" value="提交">
</form>

form 发送 POST 请求
修改上面的代码, 把 form 的 method 修改为 POST

主要的区别 :
method 从 GET 变成了 POST
数据从 query string 移动到了 body 中 .
通过 ajax 构造 HTTP 请求
在 JavaScript 中可以通过 ajax 的方式构造 HTTP 请求.ajax 全称 Asynchronous Javascript And XML, 是 2005 年提出的一种 JavaScript 给服务器发送HTTP 请求的方式. 特点是可以不需要 刷新页面/页面跳转 就能进行数据传输.
第一个 A 代表的是 异步:当你在游戏中点击一个按钮,这个按钮要去获取一些新的游戏道具信息。但你并不需要等待它获取完才能继续玩别的,你可以一边继续操作游戏的其他部分,一边让它在后台默默地去获取信息(这就是异步)。

Ajax 和 form 相比的优势在于功能更强大
1. 支持 put、delete 等方法
2. Ajax 发送的请求可以灵活设置 header
3. Ajax 发送的请求中的 body 也是可以灵活设置的
HTTPS
HTTPS(HTTP + SSL / 安全层) 也是一个应用层协议 . 是在 HTTP 协议的基础上引入了一个加密层 .
HTTP 协议内容都是按照文本的方式明文传输的 . 这就导致在传输过程中出现一些被篡改的情况 .(例如运营商劫持:想下载天天酷跑的,结果点下载的时候给的是QQ浏览器的下载链接)
为了解决这一问题,就引入了加密,HTTPS 就是在 HTTP 的基础上进行了加密 , 进一步的来保证用户的信息安全。
加密
加密就是把 明文 ( 要传输的信息 ) 进行一系列变换 , 生成 密文 .
解密就是把 密文 再进行一系列变换 , 还原成 明文 .
在这个加密和解密的过程中, 往往需要一个或者多个中间的数据 , 辅助进行这个过程 , 这样的数据称为 密 钥


就像上面的“当心肃顺,端华,戴恒”就是明文、第一张内容上扯家常就是密文、而这个带有窟窿纸就是所谓的密钥。
HTTPS 的工作过程
既然要保证数据安全, 就需要进行 " 加密 "。网络传输中不再直接传输明文了, 而是加密之后的 " 密文 "。
对称加密
对称加密其实就是通过同一个 " 密钥 " , 把明文加密成密文 , 并且也能把密文解密成明文 .
加密的过程:a(明文) + key => b(密文) 解密的过程:b(密文) + key => a(明文)

引入对称加密之后, 即使数据被截获 , 由于黑客不知道密钥是啥 , 因此就无法进行解密 , 也就不知道请求的真实内容是啥了。
但是!一开始客户端得先把对称密钥告诉服务器才行,然而在传输的过程中不就被黑客知道了吗?然后传送的数据黑客不就也可以解密了吗?为了安全把密钥给传送过去,因此就有了非对称加密。
非对称加密
非对称加密要用到两个密钥 , 一个叫做 " 公钥 "(公开), 一个叫做 " 私钥 "(私藏).
公钥加密:明文 + 公钥 => 密文 私钥解密:密文 + 私钥 => 明文(反过来私钥加密也行)

此时,就算黑客截取了信息,但由于没有私钥也就不能解密获取内容了。然后客户端就会用自己的对称密钥(明文)+ 公钥 传输给服务器端,然后服务器就可以解密出对称密钥进而双方能安全通信了。
那为什么不直接用密钥私钥进行数据传输呢?首先最大的缺点就是运算速度非常慢,比对称加密要慢很多。其次就是如果只有非对称加密,那服务器端发回响应的时候,客户端没有私钥怎么解密呢?所以,非对称加密只是用来传输对称密钥的。
然而,万一中间的黑客伪造了一个服务器响应给客户端,客户端不知道就直接把对称密钥发出去了,此时黑客就可以掌握两端发送信息的内容,并且能随意篡改了(这也被称为“中间人攻击”)。因此就引入了人证书。
证书
在客户端和服务器刚一建立连接的时候, 服务器给客户端返回一个 证书。 这个证书包含了刚才的公钥。服务器(网站)在设立之初,需要到专门的认证机构去申请证书,服务器生成的公钥也包含在证书当中。在实际中,客户端向服务器请求公钥的时候是把整个证书都申请过来的,客户端就能根据这个证书进行校验看看是否真的、有没有被修改过,否则就会弹框警告。
这个 证书 可以理解成是一个结构化的字符串 , 里面包含了以下信息 : 证书发布机构、证书有效期、公钥、证书所有者、签名......
当客户端获取到这个证书之后, 会对证书进行校验 ( 防止证书是伪造的 ). 判定证书的有效期是否过期、判定证书的发布机构是否受信任( 操作系统中已内置的受信任的证书发布机构 ).
验证证书是否被篡改: 一开始证书会根据已有内容进行一定的计算生成一个值 hash1,然后认证机构会用自己的私钥对 hash1 进行加密然后写入到签名中;客户端就会使用认证机构的公钥(操作系统内置了)对签名进行解密得到 hash1,再根据相同的计算对现有的内容再生成一个值 hash2,如果 hash1 = hash2,那么就认为没有被篡改过。因为黑客一旦对内容修改了那么生成出来的 hash2 就不等于 hash1了;如果想对签名修改的话因为没有对应的私钥,改了之后客户端这边使用公钥对签名就解不了密了。