目录
前言
在前面,我们已经讲了什么是TCP、UDP和IP协议以及以太网协议,那么本篇我们就来讲解一下在应用层的HTTP协议。
一.什么是HTTP
HTTP,全称为超文本传输协议(Hypertxt Transfer Protocol),是一种应用广泛的应用层协议,用于在网络中传输超文本(如HTML等)。是基于传输层的TCP/IP协议栈实现的,定义了客户端(如浏览器)与Web服务器之间请求和响应的格式。简单来说就是客户端发送请求到服务器,服务器再接收到请求后处理,返回响应给客户端。通常使用端口80进行通信。
超文本:就是传输的内容不仅仅有文本(如HTML、css),还可以是一些其他的资源(如图片、视频、音频等二进制的数据)
(HTTP1.0,HTTP1.1,HTTP2.0均为TCP协议,而HTTP3.0则是基于UDP实现),现在主用HHTP1.1和HTTP2.0。
HTTP协议是一种典型的“一问一答” 模型的协议。
客户端发送一个请求,服务器就会返回一个响应,这种就是一问一答的模式;
当然,还要其他的模式:
- 一问多答:如文件下载;
- 多问一答:大文件传送;
- 多问多答:远程桌面(远程控制),如腾讯会议。
HTTP报文格式
HTTP协议的报文格式分为 请求报文 和 响应报文。请求报文和响应报文的格式是不相同的。
要理解HTTP的请求和响应报文格式,我们需要借助抓包工具Fiddler来抓取HTTP的请求和报文数据报。
Fiddler的安装和使用我们已经在前面讲解,这里我们就来抓取一下报文。
我们在网页中输入百度的网址:
www.baidu.com
我们在Fiddler中就会看到:
HTTP的请求格式
我们来打开这个http报文查看一下:
在记事本打开后:
那么我们来分析一下这个请求报文的内容是什么意思。
HTTP请求的基本格式可以分为四个部分:
- 首行
- 请求头
- 空行
- 正文
1.首行
首行可以分为三个部分,每个部分之间用空格隔开。
GET:方法名,表示从服务器中请求数据;
第二部分是URI,即唯一资源定位符。用来描述一个资源在网络上的位置。
我们来分析一下URI
- http:协议方案名,常见的有http和https,也有其他类型(如访问mysql时用的jdbc:mysql);
- user:pass:登录信息,现在的网站进行身份认证一般不再会通过URL进行了,一般会省略;
- www.example.jp:网址的域名。这个可以是IP,也可以是域名。
- 80:服务器端口号,端口号不是必须的,当端口号省略时,浏览器会根据协议类型自动决定使用哪个端口。在http中,默认的端口号是80端口。而在https协议中,端口号默认是443端口号。
- /dir/index.htm:带层次的文件路径,虚拟目录部分
- uid=1:这部分是查询字符串(query string),这些参数是针对要访问的资源做额外的补充。查询字符串是从 ? 开始的键值对结构的数据,键和键之间用 & 连接,键和值之间用 = 隔开,可以有多个键值对。
我们可以在百度中搜索一下csdn,就会看到:
这是查询字符串是什么意思,我们也不知道,是由百度的程序员自定义的。这个query string 也会通过uriencode转码。
- ch=1:片段标识,主要用于页面内跳转。
2.请求头(header)
请求头部分从第二行开始的,一直到空行结束。
每一行都是一个键值对,键和值之间用 :空格 分割。
3.空行
空行是请求头结束的标记
我们可以看到抓取到的请求数据包的末尾有一个空行。
4.正文(body)
HTTP数据包中的正文(Body)通常指定是要请求或响应的数据。包含了实际传输数据的内容,在HTTP请求中,正文通常包含的是客户端要发送给服务器的数据,例如身份认证信息、表单数据;在HTTP响应中,正文部分是服务器要返回给客户端的数据,例如HTML页面、JSON数据等。
HTTP的正文是一些字节组成的(通常是1460字节大小),可以包含多种类型的数据,主要取决于HTTP请求的类型和上下文。HTTP的正文内容和格式由Content-Type头部字段指定,这个字段告诉接收方正文的媒体类型。例如,Content-Type: application/json
表示正文包含JSON格式的数据。
HTTP的正文部分是可选的,有的报文有正文,有的报文没有。
在我们抓取的百度请求数据包中,是没有正文的:
HTTP的响应格式
同样的,HTTP的响应报文格式主要分为四个部分:
- 报文
- 请求头(header)
- 空行
- 正文(body)
我们在Fiddler中来打开响应报文进行查看:
1.首行
HTTP响应报文的首行也是分为三个部分:
- HTTP版本号:描述了响应报文采用的是哪个版本的HTTP;
- 状态码:描述了服务器对客户端请求的处理结果。
状态码是由三个十进制数字组成的,第一个十进制数字定义了状态码的类型(5类),后两个没有分类的作用,状态码分为5类:
HTTP状态码列表:
- 状态码描述:状态码描述是状态码简单的文字描述,向客户端提供了简单易懂的文字描述。如:“OK”对应的状态码是200,“Not Found”对应的状态码是404,“Forbidden”对应的状态码是403等。
2.响应头
响应头也是键值对的形式,键和值之间用 :空格 分割,每个键各占一行。
3.空行
空行也是响应头的结束标记。
4.正文(body)
在抓取到的百度响应报文中的正文,是html格式的数据。
首行中的方法
在HTTP中,主要定义了以下几种请求方法来资源进行操作:
每个版本支持的方法:
虽然请求办法有很多,但是在日常使用中,GET和POST占了八成,所以我们本篇主要学习这两个方法。
GET和POST的区别
GET和POST本质上没有区别(GET能用的场景,POST也能;POST能用的,GET也能用)。
但是在使用的时候,还是有区别的,但不是本质上的区别。
1.语义不同,方法表示的含义
- GET表示从服务器中拿数据
- POST表示往服务器中提交数据
2.传递数据的方式不同
- GET传递数据,通常是通过查询字符串(query string)把自定义数据提交给服务器
- POST传递数据,通常是通过正文(body)把自定义数据提交给服务器
3.幂等性
- GET方法对应的请求,通常设计成“幂等”的
- POST方法对应的请求,对“幂等性”无要求
什么是幂等性?
HTTP中对幂等性的定义是:一次和多次请求某一个资源对资源本身应该具有同样的结果。简单来说就是,一次执行和多次执行对资源本身产生的影响是相同的。
在业务开发中,经常会遇到重复提交的情况,无论是网络问题无法接收到请求结果而重新发起请求,还是前端的操作抖动而造成的重复提交。
例如:
- 用户在APP上连续点击了多次提交订单,后台应该只产生一个订单;
- 向支付宝发起支付请求,由于网络问题或系统BUG重发,支付宝应该只扣一次钱。 很显然,声明幂等的服务认为,外部调用者会存在多次调用的情况,为了防止外部多次调用对系统数据状态的发生多次改变,将服务设计成幂等。
4.承接幂等性
- GET如果设计成幂等的,那么此时的GET的结果节可以被缓存
- POST不设计成幂等性,那么POST就不应该被缓存
Header
在Header中,键值对有很多,我们重点挑几个来讲。
Host
Host:指明了请求服务器主机的域名/IP地址和端口号。组成:域名+端口号;
如果没有给定端口号,会自动使用被请求服务的默认端口(比如请求一个HTTP的URL会自动使用80端口)
Content-length
表示正文(body)的数据长度,以字节为单位。
这个有什么用呢?可以告诉我们这个http数据报到哪里结束,我们在前面讲过,http是基于TCP的,而TCP是面向字节流的,存在着粘包问题.如果在TCP下连续传输多个HTTP数据报,那么接收方的接收缓冲区此时就会积累着多个HTTP数据包,而应用程序在读取的时候,需要知道包和包之间的边界,那么我们要读取一个包正文(body)有多长,就取决于Content-length。
对于GET这种,一般是没有body部分的数据包的,所以就需要使用 空格 来作为分隔符,而对于POST这种,一般是有正文(body)的,所以我们就需要使用 空格 和Content-Length 来进行区分。
只有有正文(body)的报文,才有Content-length 和 Content-type 这两个键值对。
Content-type
表示正文(body)的数据格式。
body的数据格式有很多种:
请求中:
- application / json :这种body就是json;
- application / x -www-form-urlencoded :这种称为form表单,通过 HTML 中的 form标签构造出来的一种格式,这种格式特点是将 查询字符串(query string) 放到body 中了。
- multipart / form-data:在上传文件的时候会涉及,但上传文件不一定都是这个格式。
响应中:
- text / plain :纯文本格式
- text / html :HTML格式
- text / csss:css格式
- application / javascript:js格式
- application / json:json数据格式
- image / png :png图片格式
- image / jpg :JPG图片格式
我们在Fiddler中抓取到的蓝色一般就是属于HTML格式的数据包;
紫色的就是css、绿色的就是JavaScript、黑色是JSON。
User-Agent(UA)
通过Fiddler抓包,我们可以看到几个常见的信息:
- Windows NT 10.0;Win64;x64:用户所使用的操作系统及其版本.
- Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0:表示我们使用浏览器的版本号
- AppleWebKit/537.36:渲染引擎,是浏览器用来渲染网页的核心组件,确保在特定的浏览器上正常运行。
UA现在主要用来辨别你使用的是PC端还是移动端,虽然可以用来辨别,但是返回的网页其实跟这个UA无关,这个UA是用来统计数据的。
Referer
Referer描述了当前页面是从哪个页面跳转过来的。如果直接在搜索栏输入URL是没有Referer的。
Referer是HHTP请求头header中的一部分,当浏览器(或者模拟浏览器行为)向Web服务器发送请求的时候,头信息里包含Referer,告诉服务器我是从哪里来的。
Referer主要有两个作用:
- 防盗链:假如我们的域名是 www.google.com,我只允许我自己的网站去访问我自己的图片服务器,那么我的域名就是 www.google.com ,那么图片服务器每次取到Referer的时候就会判断是不是自己的域名 www.google.com,如果是就继续访问,否则就拦截。
- 防止恶意请求:对于一些危险系数比较高的文件,我们可以使用referer来使得该文件只能来自我指定的网站。
Cookie
Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,浏览器会存储cookie并在下次向同一服务器发起请求时携带上并发送到服务器上。
Cookie也是键值对结构,使用;来分割键值对,用 = 来分割键和值。
例如:我们在登录一个网站的时候,如csdn、leetcode等,它们都会将用户的身份信息等存储到浏览器的cookie上,等在下一次登录的时候,我们就会发现可以直接进入主页,不再需要登录。
为了安全,浏览器是禁止网页直接访问我们的硬盘的(文件系统),防止我们在打开某个网页后,导致电脑上所有的文件都被删除了。但浏览器为了保证安全性又能保存数据,就引入了Cookie,其实Cookie也是按照硬盘文件的形式存储数据的,但是浏览器对这个文件进行了封装,网页只能往Cookie中存放键值对。
Cookie中的数据可以是由服务器返回的数据(包含Set-Cookie),也可以是自己生成的。
Cookie这样的键值对是按照 域名为维度 来分类的,一个域名下可能存在很多个cookie,后续访问哪个域名就把该域名下的cookie代入请求中发送给服务器。
我们来实验一下
首先在浏览器中输入www.baidu.com
将里面的cookie删除,再重新输入域名,打开Fiddler,再找到域名为www.baidu.com的http,打开其中的响应报文。
我们可以看到,在响应的报文中,设置了5个cookie,等我们下次再打开百度时,就会将这些cookie一同携带发送给服务器,服务器再通过这些cookie做出相应的处理。
以上就是本篇http协议所有内容咯~
若有不足,欢迎指正~