引言
1. 什么是 HTTP
HTTP:Hyper Text Transfer Protocol(超文本传输协议)
(1) 超文本
看到超文本,就可以联想到 HTML
HTML:Hypertext Markup Language ( 超文本标记语言 )
在早期的时候,HTTP 被设计出来就是为了下载 HTML,而超文本的含义,顾名思义,它并不像早期的报纸一样,只有文字和图片的排版,它更有视频、音频、链接、动态效果…等这些特殊的信息。
超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本。(来源于:百度百科)
按我个人的理解,超文本使得当代较于信息初代而言,就是让信息变得更加花里胡哨了,让信息换了不同的形式呈现在了计算机用户的面前。
(2) 传输
传输主要指的是两台计算机进行信息的交互,靠什么交互?肯定就是网络了。
客户端与服务器这样的传输模型最为常见,一般来说,客户端需要先发送请求,服务器之后再返回响应。
(3) 协议
协议就是一种约定,前面的博客有提到,不再赘述。
2. 理解 HTTP
(1) HTTP 协议属于应用层
可以看到,HTTP 协议属于应用层,应用层也是 开发人员 / 程序员 与其打交道最多的一层,这一层与 Web 开发紧密相连。
(2) HTTP 协议是一发一收的模型
此外,在网络通信中,基本上都是客户端与服务器之间的联系。它们之间的沟通一般分为:一发一收、多发一收、一发多收、多发多收。
而 HTTP 协议就是一发一收的这种模型,当然,这也是最常见的一种模型。
(3) HTTP 协议是文本格式的协议
HTTP 协议是一种文本格式的协议,所以不能直接传输二进制数据,如果是图片、视频、音频…等,需要对这些数据进行特殊编码,再进行传输。
一、理解 URL
URL:Uniform Resource Locator ( 统一资源定位器 )
URL 其实就是,俗称的 " 网址 "。互联网上的每个文件都有一个唯一的URL,它是因特网的万维网服务程序上用于指定信息位置的表示方法。URL 的详细规则由因特网标准RFC1738 进行了约定。
1. URL格式
① 协议方案名:URL支持很多种协议,例如:http, https, ftp, file…
② 登录信息(认证):现在基本已经废弃了登录信息格式;现代的做法就是:进入网页后,要求另外输入用户名和密码。
③ 服务器地址:这里不带 /。服务器地址既可以是域名,也可以是 IP 地址。
例如:www.sogou.com ( 这是一个域名,但域名本质上就是一个 IP 地址,写域名的本质只是为了方便普通用户使用,所以域名并不是硬性条件。 )
④ 服务器端口号:可写可不写,如果不写端口号,浏览器就会给一个默认端口号,http 默认值 80,https 默认值 443.
⑤ 带层次的文件路径:表示访问服务器上不同的资源,例如:HTML,CSS,JS…
⑥ 查询字符串:( query string ),查询字符串表示,浏览器给服务器传递的一些参数,开发人员可以自定义参数的内容。这些参数基本都是以键值对的方式来组织的。
查询字符串以 ? 作为起始标志。
键值对之间,用 & 分割,键和值之间,使用 = 分割
而每个键值对是什么意思,这是根据开发人员自定义来的,所以不同网页、不同公司,很大可能,键值对含义不同。
⑦ 片段标识符:不常用,通常用来定位到一个 HTML 页面中的某个具体位置。
注意
上面七个组成 URL 的要素,其实每一个都可以省略,这需要根据不同的场景来进行设定。
例如:
https://www.sogou.com/
这是我们平时登录的搜狗网站,可以看到:URL 只由协议名 https 和 域名组成,其他皆省略,那么默认端口号就是 443,路径就是 / ,表示根路径。而其他的几个元素,本来就是可有可无的。
2. URL encode
在上面的 URL 格式中,我们理解了:像【 / ? : 】等这样的字符,已经被 URL 当做特殊意义理解了,因此这些字符不能随意出现。那么,某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义。这就和 Java 中的转义字符是一个道理,但是这里的转义方式却大不相同。
特殊字符 > 转义字符: URL encode 转义字符 > 原字符: URL decode
例如:我们使用搜狗搜索【 ?+ 】这类字符的时候,就会转义成下面的形式,当然,中文也会被转义。字符遵循 ASCII 码的十六进制转换;中文遵循 UTF-8 编码转换。
注意
虽然浏览器会自动对这里的特殊符号进行 encode,但有的时候,我们需要自己手动构造的 URL,浏览器不一定支持自动的 encode。所以为了稳妥起见,我们自己构造URL中,若带有特殊符号, 一定要手动的 encode,否则就可能请求发送失败。
试想:广大电脑的使用者就是客户端,当用户上网查资料的时候,如果给服务器发送请求,但是因为特殊字符的原因,导致请求失败,那么服务器自然就无法响应,长此以往,这必然是一个重大缺陷。可能的一个原因就是:用户与用户之间使用的浏览器不同,有些非主流的浏览器并不能很好地兼容特殊字符…
例如:在前端的 HTML 中,有一个 a 标签:
二、HTTP 请求
HTTP 请求的基本格式
以下面图片为例:
HTTP 请求的基本格式一般分为四个部分:
① 首行
HTTP 请求的首行十分有特点:
【请求方法】+ 空格 +【URL】+ 空格 +【版本号】
② header 请求头:每一行都是一个键值对。
③ 空行
④ 正文 body
1. GET 方法
GET 是最常用的 HTTP 方法,常用于获取服务器上的某个资源。
哪些情况可以构造出 HTTP GET 请求呢?
① 在浏览器中直接输入 URL
② 另外,HTML 中的 link, img, script 等标签,也会触发 GET 请求。
③ 后面我们还会学习,使用 JavaScript 中的 ajax,也能构造 GET 请求。
④ form 表单
⑤ 使用 Java 代码 / 其他库
⑥ 通过 linux 下的 wget / curl
⑦ 通过第三方工具,postman 这类工具。
展示
我们在 chrome 浏览器中直接输入 URL,以搜狗首页为例,再通过抓包后,为我们呈现的请求。观察 GET 方法:
① 首行的第一部分为 GET.
② GET 后面跟了一个空格,空格后跟了当前的 URL,当前的 URL 的 【query string 】为空,这是因为我们并没有通过搜狗搜索信息。当我们搜索信息的时候,当然就不为空了。
③ header 部分有若干个键值对结构。
④ 一般给服务器发送请求情况下,GET 对应的 body 部分都为空。但也可以自己构造一个 body 不为空的请求,这需要根据不同的场景,然而,这种 body 不为空的场景较为少见。
注意
关于 GET 请求的 URL 长度问题:
HTTP 协议由 RFC 2616 标准定义,标准原文中明确说明: " Hypertext Transfer Protocol – HTTP/1.1," does not specify any requirement for URL length.
即没有对 URL 的长度有任何的限制。
然而,实际 URL 的长度取决于浏览器的实现和 HTTP 服务器端的实现。不同的浏览器设定的 URL 最大长度可能是不同的,但当代主流浏览器支持的 URL 最大长度一般都很长。
2. POST 方法
POST 方法也是一种常见的方法。多用于提交用户输入的数据给服务器 ( 例如登陆页面 )。POST 方法可以通过 HTML 中的 form 标签构造 POST 请求,也可以使用 JavaScript 的 ajax 也构造 POST 请求。
展示
我们在 chrome 浏览器中登录 QQ 邮箱,再通过 fiddler 抓包后,为我们呈现的请求。观察 POST 方法:
① 首行的第一部分为 POST.
② POST 后面跟了一个空格,空格后跟了当前的 URL。当前的 URL 的 【query string 】为空。因为 POST 的 【query string 】一般就为空,当然,开发人员也可以设计不为空。
③ header 部分有若干个键值对结构。
④ 一般给服务器发送请求情况下,POST 对应的 body 部分不为空。当然,这并不是绝对的。因为 body 中的内容是根据开发人员自己设定的,换句话说,其中的代码逻辑,只有开发人员知道。
3. GET 和 POST 的区别( 经典面试题 )
答:
HTTP 协议中的各个方法之间,尤其是 GET 和 POST ,这两者并没有本质的区别。但依然存在细微的差别,然而这些细微的差别可有可无,根据自定义情况设定。
细节上的差别,例如:
① 数据位置:一般来说,GET 请求习惯将自定义数据放到 【query string】, POST 请求则是把自定义数据放入 正文body.
② 语义区别:一般来说,GET 请求用于 获取数据,POST 请求用于提交数据。
③ 幂等性:一般来说,GET 请求会被开发人员设计成 “幂等” 的,POST请求不被设计成 “幂等” 的,
幂等:数学上的术语,某个请求,执行一次和执行多次,在结果上没有区别。
④ 可缓存:一般来说,GET 请求会被缓存,POST 请求不会被缓存。
缓存:计算机若需要通过一些复杂的、大量的计算,来得到一些结果,如果这个结果的计算过程代价太大,就可以把这样的结果事先保存下来,下次直接使用,避免重复计算了。从而提升了效率,减少了消耗。
注意
可以看到,上面的四个细节上的差别,在开头上,我都用了【一般来说】。这是因为,GET 和 POST 在细节上的区别并不是绝对的,两者的差别都是受到了开发人员设计、浏览器、实现场景等因素的影响。所以,他们之间的一些差别本身就是可以相互转换的。总而言之,在大前提上,它们没有本质区别。
此外,关于两者在【传输的安全性、传输的数据量、传输的数据类型…】等问题上,官方文档并没有给出区别说明。还是那句话,两者无本质区别,若真的有差异,这是根据开发人员的设计、浏览器、服务器…来决定的。
4. HTTP 请求的其他方法
① PUT:与 POST 相似,只是具有幂等特性,一般用于更新
② DELETE:删除服务器指定资源
③ OPTIONS:返回服务器所支持的请求方法
④ HEAD:类似于GET,只不过响应体不返回,只返回响应头
⑤ TRACE:回显服务器端收到的请求,测试的时候会用到这个
⑥ CONNECT:预留,暂无使用
我们必须明确:在HTTP 请求中,用的最多的就是 GET 和 POST。而 HTTP 请求的其他方法,作为了解即可。
5. 认识 HTTP 请求中的报头
(1) Host
Host:表示服务器主机的地址和端口。一般来说,如果我们在浏览器中输入 URL,那么,HOST 表示的信息与 URL 中的内容是一样的,但也不绝对。
(2) Content-Length
Content-Length:表示请求中 body 中的数据长度,单位是字节。如果 body 内容为空,那么,在抓包的时候,也许就看不到这个 Content-Length.
(3) Content-Type
Content-Type:表示请求中 body 中的数据类型,常见的有三种。前面提到 body 一般存在于 POST 请求中,那么下面三种情况也常对应着 POST 请求中的 body.
① application/x-www-form-urlencoded
studentID=123&classID=456
② multipart/form-data
这种类型较为复杂,主要是用来提交文件的。
③ application/json
{ "studentID": 123, "classID": 456, "age": 21, ... ... }
(4) User-Agent
User-Agent ( UA ):表示浏览器 / 操作系统的属性。
这是我通过 chrome 浏览器查询信息后,抓包的结果:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
【Windows NT 10.0】 表示 win10 的内核版本,【Win64;64】表示操作系统的版本信息,后面跟的是浏览器的版本信息。
UA 不仅能表示 PC 端的浏览器属性,还能表示移动端的浏览器属性。鉴于此,它能够区分当前设备是 PC 端 还是 移动端,从而对网页排版做出不同的尺寸。
(5) Referer
Referer:表示当前页面是从哪个页面跳转过来的。
(6) Cookie
Cookie 机制:当浏览器访问网页对应的服务器时,服务器会在 HTTP 的响应头中添加一个键值对传送给浏览器,往后每次访问此网页所属的网站时,都会在请求头中带着这个网站的所有 Cookie 值。
举个例子:你现在通过用户名和密码登录了 CSDN,这时,浏览器会向服务器发送请求;之后,服务器就会返回响应,而在响应的过程中,它给予了浏览器一个 “令牌”,告知浏览器,之后所以的操作都在你的用户名下,不管是浏览 CSDN 的文章也好、不管是自己写博客也好、不管是点赞收藏博客也好…这都基于你当前的用户名。如果要切换用户,那么只有 “退出登录” 才行。
这个过程和去医院看病很相似:到了医院先挂号,挂号时候需要提供身份证,同时得到了一张 “就诊卡”,这个就诊卡就相当于患者的 “令牌”。后续病人去各个科室进行检查、诊断、开药等操作,都不必再出示身份证了,只要凭就诊卡即可识别出当前患者的身份。看完病了之后,不想要就诊卡了,就可以注销这个卡,此时患者的身份和就诊卡的关联就销毁了。
6. body 正文
body 正文:正文中的内容是开发人员自定义的,所以,就算是很多明文的数据,也只有开发人员知道使用着什么逻辑,更别提密文了。
报头中的 Content-Type 和 Content-Length 即分别表示 body 正文的类型和字节长度。
三、HTTP 响应
HTTP 响应的基本格式
以下面图片为例:
HTTP 响应的基本格式和 HTTP 请求基本相似,一般分为四个部分:
① 首行
HTTP 响应的首行十分有特点:
【协议】+ / +【协议版本号】+ 空格 +【状态码】+ 【状态码描述】
② header 响应报头:每一行都是一个键值对。
③ 空行
④ 正文 body
1. 认识状态码(经典面试题)
状态码表示访问一个页面的结果,可能访问成功,也可能访问失败,也可能是其他的一些情况。
(1) 200 OK
200 这是一个最常见的状态码,表示访问成功。
在使用 fiddler 抓包的时候,如果成功访问某页面,那么 HTTP 的响应首行末尾就是 200 OK.
(2) 404 Not found
404 表示没有找到资源。在我们日常使用浏览器的时候,如果出现问题,很多情况下就是碰到了关于 “页面丢失的情况”,所以,404 还是较为常见的。
例如:下面的一幅图分别呈现了 搜狗访问出错和 B站访问出错,这个 404 也可以由开发人员自行设计。
(3) 403 Forbidden
403 表示访问被拒绝,有的页面通常需要用户具有一定的权限才能访问。
比方说:程序员使用 gitee 码云仓库,如果用户将一些仓库设为私有,那么其他用户访问这些私有仓库的时候,就会出现 403.
(4) 405 Method Not Allowed
前面我们已经学习了 HTTP 请求中所支持的方法,有 GET, POST, PUT, DELETE…等。一旦我们使用了这些方法,在我们的视角来看,这是没问题的。但访问对方的服务器,不一定都支持所有的方法,或者说,访问的服务器限制了用户使用一些方法。那么此时,就会出现 405.
(5) 500 Internal Server Error
500 表示服务器出现内部错误,一般是在服务器的代码执行过程中遇到了一些特殊情况,比方说:服务器异常崩溃。
(6) 504 Gateway Timeout
504 表示网关超时。具体来说,当服务器负载比较大的时候,服务器处理单条请求的时候消耗的时间就会很长,就可能会导致出现超时的情况。
例如:
双十一 “秒杀” 场景;省级 / 国家级考试后,网上查分数线的时刻。
(7) 302 Move temporarily
302 表示临时重定向。具体来说,在登录页面中会经常见到 302,其用于实现登陆成功后,自动跳转到的某个页面。而 head 响应报头中的 Location 字段,即表示要跳转到的某个页面。
普通用户在使用浏览器的时候,基本见不到 302,只有通过抓包才能看到,302 状态码相当于一个瞬移功能," 从某一个链接跳到另一个链接 "。
例如:我通过 Chrome 浏览器,使用网页登录 QQ 邮箱后,Location 字段就立即记录下来接着要跳转到哪个地址上,从而,浏览器就会根据 Location 中记录的 URL,立即访问这个 URL.
(8) 301 Move parmanently
301 表示永久重定向。当浏览器收到这种响应时,后续的请求都会被自动改成新的地址,另外,301 也是通过 Location 字段来表示要重定向到的新地址。
状态码总结
2. 认识 HTTP 响应中的报头
HTTP 响应中的报头和 HTTP 请求中的报头 相比,两者格式类似,都是键值对的形式。但 Content-Type 对应的类型有很大不同。
(1) Content-Type
响应中的 Content-Type 常见取值有以下几种:
text/html: body 数据格式是 HTML text/css: body 数据格式是 CSS application/javascript: body 数据格式是 JavaScript application/json: body 数据格式是 JSON image/png body 数据格式是 图片经过特殊处理后的文本形式
3. body 正文
HTTP 响应中的 body 正文与 HTTP 请求中的 正文 相比,两者大不相同。body 正文常见的内容基于 Content-Type.
四、拓展
1. 多使用 fiddler 抓包
HTTP 协议比较抽象,如果我们真的想要理解 HTTP协议 的来龙去脉,还是以 【抓包为主】,毕竟实践出真知,并且抓包后为我们呈现的结果,可以很清晰地让我们理解到,整个页面通过网络,做了些什么事情。
2. CtrI + F5 和 F5
一个页面,不仅仅只有一个 HTML 文件,还会依赖很多其他的资源,例如:CSS, JS,图片…这些资源其实都是通过网络,下载到浏览器本地的。
为什么呢?
现在这个时代,经常使用浏览器的人都知道,很多网页做的非常精美。所以一个网页依赖的资源可能很多很大,网络传输速度又不快 ( 相对于访问内存 / 磁盘 ),这个时候加载页面就会比较慢。浏览器就会把这些依赖的资源直接缓存到本地,后续再访问的时候速度就快了(已经缓存过的资源,就不必重新下载了)
CtrI + F5 表示强制刷新。
不会重复利用缓存数据,直接清空缓存,把所有的资源重新下载。
F5 表示刷新。
但仍然会重复利用缓存的数据。
有时候我们抓包,如果抓不到想要的结果,就可以尝试在当前页面中,使用 CtrI + F5,来个强制刷新,这样会使得抓包效果好上很多。