目录
1、HTTP的概述和抓包工具的使用
1.1、HTTP是什么
HTTP全称为超文本传输协议,是一种应用非常广泛的应用层协议。HTTP协议往往是基于传输层的TCP协议实现的。HTTP1.0、HTTP1.1、HTTP2.0均是基于TCP实现的,HTTP3是基于UDP实现的。目前我们主要使用的还是HTTP1.1和HTTP2.0。在本章博客中,主要还是了解HTTP1.1版本。
所谓"超文本"的含义,就是传输的内容不仅仅是文本(像前端的html、css这就是文本),还可以是一些其他的资源,比如图片、视频、音频等二进制数据。
我们平时打开一个网站,浏览器获取到并显示出来的页面就是通过HTTP传输的。当我们在浏览器中输入一个必应的"网址(URL)时",浏览器就给必应的服务器发送一个HTTP请求,必应的服务器返回了一个HTTP响应。这个响应被浏览器解析之后,就显示成我们看到的页面内容。这个过程中浏览器可能会给服务器发送多个HTTP请求,服务器会对应返回多个响应,这些响应里就包含了页面HTML、CSS、JavaScript、图片、字体等信息。
HTTP的使用场景非常多,你只要在上网,就在使用HTTP协议。浏览器打开一个网页会用到HTTP协议,手机app从网络上加载一份数据也会用到HTTP协议、微信小程序,支付宝小程序都在使用HTTP协议。我们打游戏时,游戏的一些界面也在用到了HTTP协议。
1.2、了解HTTP协议的工作过程
当我们在浏览器中输入一个"网址",此时浏览器就会给对应的服务器发送一个HTTP请求,对方服务器收到这个请求之后,经过计算处理,就会返回一个HTTP响应.(HTTP是一个"一问一答"这种形式的协议)。
实际上,当我们访问一个网站的时候,可能涉及不止一次的HTTP请求和响应的交互过程。
1.3、抓包工具的使用
我们学习HTTP协议,最主要的就是认识HTTP的报文协议格式,想要认识HTTP的报文格式,就需要借助一些外部的工具,来把HTTP协议显示出来。这个时候需要一个第三方工具,对网络上传输的HTTP报进行抓取。
本章博客主要介绍Fiddler这个抓包工具,但是有的老铁的浏览器中下载了一些插件,可能和Fiddler会产生冲突,出现抓包不成功等等的问题, 这个时候我们可以使用Charles这个抓包工具,也可以使用浏览器自带的抓包功能。
🍂先来看浏览器自带的抓包功能
1.3.1、抓包工具在HTTP传输时的工作原理
在没有抓包工具的情况下,浏览器的请求和服务器的响应数据都是直接通过网卡交给对方。
抓包工具就相当于一个"代理"。借助这个代理我们就可以看到网络上传输的具体数据。浏览器在访问baidu.com时,就会把HTTP请求先发给抓包工具,抓包工具再把拿到的请求转发给baidu的服务器,当baidu服务器返回数据时,抓包工具拿到这个数据,在把数据交给浏览器。所以抓包工具对于浏览器和baidu服务器之间交互的数据细节,都是非常清楚的。
就好比家里做饭的时候没有酱油了。这个时候你爸爸给你钱让你跑腿去买,你来到超时把钱给老板,老板把酱油给你。这个过程中,你相对于"你爸爸"和"超时老板"之间的交易细节,是非常清楚的。
1.3.2、Fiddler抓包工具的下载和使用
Fiddler这个抓包工具,专注于抓取HTTP报,可以点击这里的官方网站fiddler下载地址进行下载安装。Fiddler的下载安装很简单。但是安装完成之后,还需要注意下面几点。
✨注意事项
- Fiddler安装好之后,只能抓取http的报,现在绝大部分浏览器使用的是https,这就导致无法解析https数据,抓到的报就很少。还有在勾选https时,会弹出一个对话框,这个询问是否安装根证书,需要点击是,点错了就需要把Fiddler卸载重新安装。
- Fiddler作为一个代理,可能会和你电脑上其他的代理冲突,比如一些浏览器插件、加速器等等,在使用Fiddler的时候需要关闭这些程序。
首先找到Tools选项,选择Options,找到HTTPS
点击之后出现的弹窗中,将HTTPS选中,然后将下边的四个选项全部勾选,此时会跳出一个弹窗,只需要一直点击是就可以。不能点错了,错了就需要重新安装了。
🍂Fiddler的使用
当我们在浏览器上输入百度的地址,访问百度主页的时候,就会产生很多的报。在Fiddler中左侧窗口显示了抓取的所有的HTTP/HTTPS请求和响应的报,这些包中,通过颜色看,黑色的包表示这个响应是一个普通数据;蓝色的包表示响应的是html;绿色的包表示响应的是JS。这些包都是我们在访问百度页面时,服务器响应的包。我们最需要关注的蓝色的包,我们访问百度页面,百度服务器响应的包就在里面。如下图。
双击要关注的包,右侧就会显示详细信息,右上是请求,右下是响应。点击右上Raw,显示的最原始的请求数据。在请求栏中显示的看不清楚,可以点击View in Notepad,打开一个记事本显示请求数据。
显示出来的就是一个完整的HTTP请求,所谓HTTP请求,其实就是通过代码,构造出一个符合HTTP格式要求的字符串,向tcp的socket中写入就可以了。显示出来的HTTP请求我们可以看懂,说明HTTP是一个文本数据,不是二进制数据。
来看一下响应的数据,点击Raw,显示原始的响应数据,可以看见在正文部分出现了乱码。响应HTTP本身是文本数据,这里显示乱码的原因是为了节省网络带宽,将数据进行了压缩。这样是用cpu资源换带宽资源。
想要查看被压缩的数据,需要点击下图中标注出来的位置,就可以解压缩。展示文本数据。
2、HTTP协议格式
✨空行的作用
- 因为HTTP协议并没有规定报头部分的键值对有多少个,空行就相当于是"报头的结束标记",或者是"报头和正文之间的分割符"。
- HTTP在传输层依赖TCP协议,TCP协议是面向字节流的,如果没有空行,无法区分报头和正文部分,就会出现"粘包问题"。
2.1、HTTP 请求格式
2.1.1.基本格式
HTTP的请求报文包括首行、请求报头(Header)、空行、请求正文(Body),我们通过抓取到HTTP包,来了解一下。
🍂GET请求:在很多地方都可看到
🍂POST请求 :在登录操作和上传文件的时候可以看到。
GET请求中大多数情况不会存在请求正文部分,有的时候也存在正文部分。POST请求中存在请求正文部分。
2.1.2、了解HTTP请求包中的首行
这里我们来看一下首行,是由三部分组成,HTTP方法,URL和版本号。这三个部分中间由空格隔开。
- HTTP方法描述了这个HTTP请求想要做什么,比如GET表示从服务器获取资源。PSOT表示往服务器中提交信息。
- URL是唯一资源定位符,描述了网络上的唯一的一个资源,URL在很多协议中都有用到,就像之前的JDBC的博客中也有说到。
- 最后一个表示了所使用的HTTP的版本。
🍂、认识URL
URL就是我们俗称的"网址",用来访问网络上的一些资源。互联网上的每个文件都有一个唯一的URL。URL的详细规则有因特网标准RFC1738进行了约定。通过下面的图片了解一下URL的具体格式。
一个完整的URL结构表示的意思就是:当前这个URL是给https协议使用,通过域名表示去bing的服务器去找(定位到了bing的服务器),在https协议指定的443端口(端口号定位到了服务器主机中的程序),通过带层次结构的路径定位到了我们要访问的资源,查询字符串表示对请求的资源进行细节上的补充。
- 协议名:常见的有http和https.
- 域名:表示的是服务器的地址,域名通过DNS系统解析成一个具体的IP地址。
- 端口号:描述访问服务器主机上的那个程序。使用":"号和域名分隔,端口号可以省略,也可以写在URL结构中,如果省略了,浏览器会根据协议类型自动决定使用那个端口,http的默认端口号为80,https默认的端口为443.
- 带层次的文件路径:表示要访问的服务器上指定位置的资源。
- 查询字符串(query string):本质一个键值对结构,键值对之间使用 &分隔,键和值之间使用=分隔。对请求的资源进行细节上的补充。查询字符串中的内容完全是程序员自己约定的,我们可以通过这样的方式来自定制传输我们需要的信息给服务器。
我们可以通过下面这个例子来理解URL。
🍂、HTTP方法
我们可以看到抓取的有些包中首行中的方法为GET,有些为POST,这些方法的作用是来告知服务器请求的意图,GET方法就是从服务器获取资源,POST是向服务器上传资源。在实际的使用中,这两种方法使用的非常多,其他的大部分方法使用不到。虽然说不同的方法,具有不同的语义,这些语义仅仅是建议这个方法的使用时机,但是实际开发中,这些语义只是用来参考,可以使用POST方法去获取资源,也可以使用GET方法去上传资源。所以这两个方法没有本质上的区别,但是在使用习惯上还是存在区别的。
📒GET方法:获取资源
GET方法是最常见的HTTP方法。常用于获取服务器上的某个资源,在浏览器中直接使用URL(网址),此时浏览器就会发出一个GET请求。HTML中的link、img、script等标签也会触发GET请求。
GET请求报文首行中URL的query string可以为空,也可以不为空,请求报头中存在若干个键值对,正文主题部分可以为空(常见),也可以不为空(不常见)。
GET请求的URL长度问题:HTTP协议有RFC2616标准定义,标准原文中明确说明了,URL的长度不受任何的限制。实际URL的长度取决于浏览器的实现和HTTP服务器端的实现。在浏览器端,不同的浏览器URL最大长度是不同的,但是现代浏览器支持的长度一般都很长;在服务器端,一般这个长度是可以配置的。
📒POST方法:上传资源
POST方法也是一种常见的方法,多用于提交用户输入的数据给给服务器,例如登录页面,通过HTML中的form标签可以构造POST请求。
POST请求中URL的query string一般为空,也可以不为空,header部分有若干个键值对结构,body部分一般不为空。body内的数据格式通过header中的Content-Type指定,body的长度由header中的Content-length指定。
2.1.3、GET和POST方法的区别(面试题)
GET和POST方法表示的语义不同,但是这里的语义在实际开发中,也仅仅只是建议的作用,程序员不一定遵守。对于请求正文(body),GET请求的body,一般情况下没有,但是还存在一些情况有,但是非常的少见。POST请求的body,一般情况下是存在的,也可以没有,但是非常少见。
- GET和POST方法在本质上没有什么区别。但是在使用习惯上存在区别。
- GET习惯上用来表示"获取资源",POST用来表示"上传资源"。
- GET一般没有body,需要携带数据则放到URL中,POST一般有body.
- GET请求通常会设计成幂等的,POST则无要求
- GET可以被缓存(前提是设计成幂等的),POST不能被缓存。
上面提到了两个概念,一个是幂等,一个是缓存。下面我们来了解一下。
🍂幂等
如果输入一定,输出一定,这种情况就可以认为是幂等的。比如奶牛吃进去的是草,挤出来的是奶,这就是幂等的,但如果吃进去的是草,挤出来的是啤酒,这就不是幂等的。
🍂缓存
- 缓存无处不在。比如我们在浏览器上搜索5!是多少,此时浏览器就会访问服务器,服务器计算好之后,这里时候可能服务器把计算的结果存起来了,下一次再有流量器访问5!,就可以直接返回给浏览器。
- 浏览器拿到服务器返回的数据之后,可能也会保存在下来,下次再查询5!,浏览器就直接将存起来的结果显示出来,不用访问服务器了。
- 因为浏览器也是一个程序,也有可能CPU直接将这个结果存在缓存中,下次还想查询,不必访问其他设备,通过本地就可以显示出来。
- 当你知道了这个结果,记住了,下次又遇到这个问题,直接就知道了结果,这也可以理解为缓存
2.1.4、请求报头的字段
header的整体的格式也是"键值对"结构。每个键值对占一行,键和值之间使用":"冒号和" "空格分割、header中可以有N行键值对, 用空行作为结束标记,header中的键值对,大部分都是HTTP协议规定好的,当然这里也是可以添加自定义的键值对。下面来了解几个常见的键值对。
- Host
这个字段描述了浏览器访问的服务器所在的地址和端口,大多数的情况下,Host中的值,和URL中的域名是一致的,但是当我们不是直接访问,而是通过"代理"来访问服务器,这里的Host和URL就不一致了。当然这里的"代理"并不是指Fiddler。通过代理访问服务器时,Host表示的就是最终目标,URL表示的就是当前的目标。
- Content-Type
描述了body的数据格式。上图中这个属性存在两个值,一个为application/x-www-form-urlencoded表示的是body数据是按照某种格式组织的,一个是charset=UTF-8表示的是数据的字符集。
如果是请求的报Content-type组织数据的常用方式有两种,一种是application/x-www-form-urlencoded组织数据的方式是form表单提交数据时,会生成这种格式的body。此时body的格式就和query string(查询字符串)的格式一样了。另外一种的组织方式josn格式,此时body的数据格式就像JS的对象一样(var a={"username" : "test","password":"123"})。
如果是响应的报Content-type组织数据的常用方式就会更丰富。就像application/javascript、application/json、image/jpg、image/png、text/html、text/css等等。
- Content-Length
描述了body的长度,单位是字节。Content-Type和Content-Length这两个属性和body有关,如果HTTP报文中有body,这两个属性再Header中存在,如果没有body,那么再Header中没有这两个属性。就像上图中的body的长度为44个字节。
- User-Agent(简称UA)
描述了客户端的浏览器和操作系统的版本。再互联网发展的开始,浏览器的种类很多,功能层次不齐,对于网站开发来所,难度就大大提升,为了兼容不同的浏览器,这个时候就出现了User-Agent,它可以再请求报中,告诉网站服务器当前上网的设备的操作系统和浏览器版本,此时服务器就可以根据客户端的种类,返回不同的页面。而现在UA的一个重要用途就是用来区分用户是手机端还是PC端还是平板。
- Referer
描述了当前这个页面,从哪个页面跳转过来的。如果直接在地址栏中输入URL,此时请求报中没有referer这个属性,当然点击收藏夹和直接输入的效果是一样的,都没有这个属性。
就像我们查询一些东西的时候,点开一个页面,页面的前几个必定是广告,这个时候你不小心点了一下,跳转到这个页面。这个时候你通过Fiddler进行抓报,就可以看见其中有Referer这个属性。
- Cookie
Cookie的值,也是键值对,键值对之间使用";"号分隔,键和值之间使用"="号分割,Cookie中的键值对表示的含义只有开发这个网站的程序员知道,这些键值对都是程序员自定义的数据。不同的网站Cookie就有不同的键值对,所以Cookie中键值对就有了不同的用途和含义。
浏览器中是需要存储一些数据的,但是为了使用户上网能比较安全,浏览器会禁止网页直接访问硬盘。所以浏览器就提供了Cookie机制,允许网页向浏览器这里存储一些自定义的键值对,这些数据通过浏览器提供的api,写入特定的文件中。
网页有很多,相同网站的网页会共享一个Cookie,每个网站都有自己的Cookie,Cookie是按照域名位维度进行存储的。
Cookie机制相当于是给HTTP增加了"记忆能力"。Cookie相当于服务器给每个客户端都贴上了一个标签,上面写了一些只有服务器才能理解的数据,需要的时候客户端把这些信息发给服务器,服务器看到Cookie,就能够知道对方是谁了。
1️⃣Cookie从哪里来?
当用户第一次通过浏览器访问服务器的时候,服务器肯定不知道它的身份,所以服务器就会在HTTP响应中,通过Set-Cookie字段,把Cookie的键值对,返回给浏览器,浏览器就知道这是对它的身份标识,浏览器收到这个数据之后,就会在本地存储。
我们通过抓包开看一下。下面这个图是服务器返回的响应HTTP报
通过下面的操作就可以在浏览器中查看的Cookie,这里就是通过Set-Cookie字段把服务器响应的HTTP报文中的Cookie键值对,返回给了浏览器,并保存在了本地。
2️⃣Cookie到哪里去?
Cookie会在浏览器下次发送请求的时候,把Cookie带给服务器。Cookie在浏览器这里只能算是暂存,真正要让这个数据发挥作用,还是得由服务器来使用。
3️⃣Cookie有啥用?
Cookie是浏览器本地存储数据的机制,能够存储任何的字符串数据。不一定非得是身份信息。由于Cookie存储空间有限,一般不会用Cookie存太大的数据(例如:视频,图片)。
Cookie最典型的应用就是用户的身份识别和状态管理,里面存的内容发挥的作用类似于"联系上下文".服务器通过客户端浏览器,把一些数据临时写入用户的计算即内,接着当用户访问该服务器时,可通过通信的方式取回之前发放的Cookie。
一个服务器要给多个客户端服务。服务器不可能去记录每个客户端的状态,服务器返回给客户端的Cookie就保存了当前用户所使用客户端的"身份"信息,当客户端下一访问服务器时,就会自动的把Cookie的内容带入到请求中,服务器就可以根据Cookie中的"身份"信息查询从而得知客户端上一次访问的中间状态以进行下一步的响应,所以说,Cookie来自于服务器,最终还是要回到服务器。
这里就像是一个登录界面,当你登录一次之后自动就会记录了登录状态,在有效期内访问就不需要重复登录了。直接就进入到了登录之后的页面。当然如果你换了一台电脑,新的浏览器中没有服务器响应的Cookie,就像脱掉了贴着标签的衣服,访问服务器,服务器也就认不出来了,只能在走一遍Set-Cookie流程。
2.2、HTTP响应格式
2.2.1、基本格式
HTTP响应的报文格式于HTTP请求的报文格式一样,是由首行、响应报头(header)、空行、响应正文(body)组成,报头和正文之间使用空行隔开。
我们使用Fiddler抓一个请求的报,来进行了解。
首行是由HTTP版本号、状态码、状态码描述构成,这三个中间使用空格隔开。状态码是一个数字,用数字表示请求执行的成功还是失败以及失败原因;状态描述码是通过一个或者一组单词,描述这个状态码的含义。就像上面的图片首行中,200就是状态码,OK就是状态描述码。
响应报头(header)中常见的属性和请求报头一样,这里就不做解释了。
响应正文(body)就是服务器返回一个页面的HTML代码、CSS代码、图片等内容。
2.2.2、状态码(面试必问)
状态码表示的是当客户端访问一个页面的时候,向服务器发送了一个HTTP请求,服务器返回的响应中就使用状态码表示访问这个页面的结果,是成功了还是失败了,还是有其他的一些情况。
HTTP的状态码的种类:
类别 | 原因短语 | |
1XX | Informational(信息性状态码) | 接收的请求正在处理 |
2XX | Success(成功状态码) | 请求正常处理完毕 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
常见的状态码:
1️⃣2XX类型的状态码
- 状态码:200 状态码描述:OK
这个状态码表示的意思就是请求成功。这个状态码非常常见,比如我们访问一个页面使用Fiddler查看抓到所有包的状态。
2️⃣3XX类型的状态码
- 状态码:302 状态码描述:Move temporarily
这个状态码表示的意思为临时重定向。
来了解一下"重定向",就是访问旧的地址,被自动引导到新的地址上。就像手机的"呼叫转移"功能,比如我手机原本的号码是123-4567-8912,现在换了一个手机号为987-6543-2109,然后办理了呼叫转移的业务,这样即使其他人不知道我新的手机号码,只要拨打我原本的手机号码,就会自动转移到现在新的手机号码上。
临时重定向表示的意思就是,这次访问的时候,进行了重定向,下次访问的时候不确定还要不要重定向。
- 状态码:301 状态码描述:Moved Permanent
这个状态码表示的意思就是永久重定向。
永久重定向表示的意思就是,请求的资源已经被分配了新的URL,以后要使用资源现在所对应的URL。
3️⃣ 4XX类型的状态码
- 状态码:404 状态码描述:Not Found
这个状态码表示的意识是没有找到资源。这个我们浏览网页的时候,最常见的一个状态码。当我们在浏览器上输入一个URL,目的就是为了访问对方服务器上的一个资源,如果这个URL标识的资源不存在,就会出现404.
例如,我们输入www.baidu.com/abc.html,此时表示访问baidu上的/abc.html这个资源。显然这个资源是我们现编的,百度服务器上没有这个资源,所以显示的页面上就会显示404.
- 状态码:403 状态码描述:Forbidden
这个状态码表示访问被拒绝(没有权限)。就像我们在发布博客的时候,设置了看见权限,普通用户就不能访问粉丝可见的博客页面。
4️⃣5XX类型的状态码
- 状态码:500 状态码描述:Internal Server Error
这个状态码表示的意思为服务器内部错误。一般四服务器代码执行过程中遇到了一些特殊的情况(服务器异常崩溃)会产生这个状态码。我们在互联网上不容易见到,但是在我们自己写代码的工程中,非常常见。
- 状态码:504 状态码描述:Gateway Timeout
这个状态码表示的意思为服务器访问超时了。浏览器给服务器发送请求,服务器要返回一个响应,结果服务器迟迟没有响应。这个状态码出现的概率是比较小,但是在春运的时候可能会出现。