什么是HTTP协议
HTTP协议是应用层中的一个比较出名的协议,HTTP协议往往是基于传输层的TCP协议来实现的.
![](https://i-blog.csdnimg.cn/blog_migrate/10959e8c3be358c7d8a7035f897f89a0.png)
当我们在浏览器中打开一个URL(网址)时,浏览器会根据这个URL构造出一个HTTP请求发给服务器,然后服务器会返回一个HTTP响应(包含了html、css、js......),然后浏览器将得到的响应数据显示出来(显示的这个过程叫做渲染)
浏览器发给服务器请求,本质上就是给TCP的socket里写了一个符合HTTP格式的字符串.
若要看清楚这个请求和响应的过程就需要进行一个抓包操作.
抓包
此处我使用的是Fiddler这个工具.
Fiddler其本质是一个代理程序.
代理可以分为两种,一种是正向代理,一种是反向代理.
正向代理代表的是客户端的代理,反向代理代表的是服务器的代理.
如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/c248c776ffb668887205a003f99ef368.png)
我给室友钱让他帮我买糖,我是发出请求方,是客户端,室友就相当于我的代理,此时这个代理就称之为正向代理.
超市是服务方,老师老板找了一个超市前台为代理,此时这个代理就称之为反向代理.
回归抓包.
当我在电脑上打开Fiddler之后,再打开一个网站,此时Fiddler上面就会拦截到一些信息.
比如我打开搜狗搜索:https://www.sogou.com/
此时在我Fiddler上面就会收到这些信息:
![](https://i-blog.csdnimg.cn/blog_migrate/da9d5855bff6d95d4b8a73428c18548a.png)
其中这个划红线的这条就是页面信息.
将其点开之后会看到和其相关的请求和响应
![](https://i-blog.csdnimg.cn/blog_migrate/94179bf581e58c889a59775047ef11ac.png)
观察抓包结果,可以看到,当前HTTP请求和响应都是一个 文本行 格式的数据(响应的数据原本是二进制,我进行解压缩了)
了解了上面这些内容,接下来就可以对HTTP的请求和响应进行解析了.
认识HTTP请求
认识URL
URL中有四个关键部分:
域名/IP
端口号
带层次的路径
查询字符串
如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/6880307d027b12ae31b8f4ca4a43cf67.png)
其中,服务器地址代表的就是域名,也就是IP.
服务器端口号描述的是当前程序的端口号,通过端口号就可以找到程序.
带层次的文件路径,可以通过它来找到程序管辖下的某个文件
查询字符串,获取资源时带的参数.
举个例子来解释上述的属性:
比如我像向我室友推荐我们学校的餐厅的一家餐饮.
我首先要描述它的位置:黑工程三餐厅(IP地址) 5号窗口(端口号)
然后描述它的餐饮名:黑工程卷饼(带层次的路径)
然后描述怎么配料好吃:辣度=中辣;葱=多葱;酱料=正常....(查询字符串)
组合起来:
![](https://i-blog.csdnimg.cn/blog_migrate/b5b0a9bac1602fa70a51f93896569deb.png)
不过我们也可以发现:在https://www.sogou.com/这个网站里面有一些属性是没有的.
同时也表示URL的组成部分有一些是可以省略的.
上述网址中的路径其实并没有省略,"/"代表的是根目录,也就是HTTP服务器的根目录.
HTTP服务器是系统上的一个进程,可以委托这个服务器管理系统上的一个特定目录,这个目录里面的资源都可以上外界访问.
比如省略端口:省略端口的时候,浏览器会提供默认端口,对于http来说,默认端口为80;对于https来说,默认端口为443
省略查询字符串:查询字符串这个属性若是没有就全凭服务器方进行分配.
查询字符串(query string)的格式:以 ? 开头,以键值对的方式组织,键值对之间使用 & 分割,键和值之间使用 = 分割.
比如:
![](https://i-blog.csdnimg.cn/blog_migrate/19a880c850de9662c0d28e8a74a7831b.png)
URL中还有转义字符(urlencode)这样的概念
比如这个 url 在query string后面就有几个中文:
![](https://i-blog.csdnimg.cn/blog_migrate/19a880c850de9662c0d28e8a74a7831b.png)
将网址复制下来就变成了:https://www.sogou.com/sogou?query=%E8%B4%AA%E7%8E%A9%E8%93%9D%E6%9C%88
可以看到"贪玩蓝月"这几个字变成很多% + 十六进制数字的形式
因为URL有些字符是有特定含义的,此时就需要对内容进行重新编码,如果不编码,直接写中文,可能浏览器就无法正确识别了.
认识方法
我们继续拿前面的 搜狗搜索 来举例
![](https://i-blog.csdnimg.cn/blog_migrate/c7a6add0fcc8c1863061a39b5e8cea1a.png)
这是打开搜狗搜索页面的请求
首行,也就是第一行,里面的GET就是方法;后面的一串是URL;最后面的 HTTP/1.1 是版本号
HTTP协议中的方法有很多,如下(比较常见的一些方法):
![](https://i-blog.csdnimg.cn/blog_migrate/108e0d2eb376d1a701068ce36704eb57.png)
这么多方法里面,GET和POST方法最为常用.
很多操作都会触发GET请求,比如:
在浏览器地址栏里直接输入URL
html里面的link,script,img...
通过js去构造GET.等等...
GET请求的特点也很明显,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/7d5a2b7b5fed10246fab1346e95ffdfd.png)
触发POST最典型的就是登录,上传文件这样的操作.
比如我进行gitee登录,此时就可以抓到触发POST方法的请求
![](https://i-blog.csdnimg.cn/blog_migrate/e04eb574097bc0281aad0a4a72eb3493.png)
POST的特点如下:
![](https://i-blog.csdnimg.cn/blog_migrate/915ec1491440683fb435b9dfc35eef96.png)
由GET和POST这两个例子可以得出:HTTP请求主要分为四个部分
首行
请求头(header)
空白行
正文(body)
并且我们可以看到GET和POST的一些区别
GET和POST的典型区别
1.GET一般没有body,GET给服务器传递信息一般都是放在query string中;POST传递消息则是通过body.
2.GET请求一般是用于从服务器获取数据;POST一般是用于给服务器提交数据.
3.GET通常会被设计成幂等;POST不要求幂等.
(幂等:相同的输入,得到的结果也相同.不幂等结果会出现不相同)
4.基于第三条,GET可以被缓存;POST一般不能被缓存.
以上的这四条区别,其实都只是使用习惯,若是程序员想,完全可以将这些区别都反过来(比如:使用GET提交,使用POST获取;将POST设定成幂等,GET设定成不幂等....),所以GET和POST没有本质上的区别.
在大部分场景下,GET和POST彼此之间都可以相互替代.
认识请求"报头"(header)
![](https://i-blog.csdnimg.cn/blog_migrate/0ccc38824093f47b0bd4dd251c9ea6cc.png)
上图中被红框圈起来的部分就是header了.
header这里就是一堆键值对,它的每一行都是一个键值对,键和值之间用 : 进行分割
这些键值对都是HTTP事先定义好的,每一个都其特定的含义.
![](https://i-blog.csdnimg.cn/blog_migrate/94467307b225b723766d54a21a843411.png)
Host
Host大概描述了服务器所在的 地址 和 端口
Host 这里的 地址 和 端口 是用来描述最终要访问的目标的.
这些内容大概率是和URL一样的,但是也会有一些情况不同,比如:使用代理服务器.
![](https://i-blog.csdnimg.cn/blog_migrate/88f039739abcf9a631cebabbc00176dc.png)
Content-Length 和 Content-Type
这两个通常是一起出现的.
如果是GET请求,没有body,则请求中没有这两个字段.
如果是POST请求,有body,则请求中有这两个字段.
Content-Length 是描述body里面的数据长度,上图中这个属性的数值为478,就说明当前请求中的body的长度就是478.
Content-Type 是描述body中数据格式
![](https://i-blog.csdnimg.cn/blog_migrate/75584d88ab73113a0e086395aa0f4bd7.png)
Content-Type 的取值有很多种:
text/html 、text/css
image/png 、image/jpg
application/javascript 、application/json
等等....
form构造的body标签就是上面的这个格式.
![](https://i-blog.csdnimg.cn/blog_migrate/f00123687c1ada8b6e9c4d55b5365f7e.png)
User-Agent
User-Agent主要描述了当前的操作系统版本和浏览器版本.
早期的浏览器只支持文本,后来浏览器可以支持图片,支持视频,音频...
此时就选择将浏览器分成多个版本,判断请求的User-Agent去判断这个网页是否要带图片,是否要带视频...
现在的User-Agent主要用来区分是 PC端 还是 移动端 来去改变网页的设计.
![](https://i-blog.csdnimg.cn/blog_migrate/2d89fd8600b80d954913fc7b8256be37.png)
Referer
Referer描述的是当前页面的"来源",是通过哪个页面进行转换的....
但是Referer也不是任何情况都有的,比如:我直接在网址栏里面输入URL,或者直接点击我的收藏夹,此时没有转接,也就没有Referer了.
![](https://i-blog.csdnimg.cn/blog_migrate/a110fb8716365aa530542d2b94259d2f.png)
Cookie
Cookie是一个很重要的header属性.
它本质上是 浏览器 给网页提供的一个 持久化本地存储 的机制.
因为为了保证主机的安全,网页默认是不允许访问计算机硬盘的.但是网页还需要存储一些数据在本地.
Cookie 的存在就是为了让网页存储一些类似于 PCB里面的"上下文" 这样的内容.
而Cookie里面具体会存放什么内容,则是由设计它的程序员来决定的.
Cookie来源于哪里?
Cookie中的数据是来自于服务器的,服务器会通过HTTP响应的报头部分(Set-Cookie 字段)来传递.
同时,也是服务器决定,当前浏览器的Cookie要存放什么内容.
Cookie存储在哪里?
Cookie是存在浏览器中的,也可以认为是存在硬盘中的.
Cookie在存的时候,是按照 浏览器+域名 来进行细分的.不同的浏览器会各自存储各自的Cookie.同一个浏览器的不同域名,会对应不同的Cookie.
Cookie要回到哪里去?
Cookie最终还是要回归到服务器的.
因为Cookie本质就是一个记录"上下文"这样的状态.
客户端这里会通过Cookie来记录当前使用的中间状态,当客户端再次访问浏览器的时候(发送请求),会自动将Cookie里面的内容代入到请求中,服务器就可以通过Cookie来知道客户端当前的状态.
Cookie里面存放了什么?
Cookie里面存放的内容由设计它的程序员决定.
![](https://i-blog.csdnimg.cn/blog_migrate/613cb23937ea2ac02c0531ae6ec44c80.png)
可以看到,Cookie中存放了很多的键值对,还可以存放过期时间等数据.
比如,有一些网站,登录过一次之后,过了一段时间,再次登录会恢复登录状态.
这就是Cookie中的过期时间记录了登录状态.
当然这个过期时间可长可短,由程序员设定.
比如下面这个时间就可以达到2026年
![](https://i-blog.csdnimg.cn/blog_migrate/2ca03dce59b392ffa9da5f64cad7ddb3.png)
再比如,存放内容比较敏感的网站,比如一些和支付相关的网站,可能刚关闭页面,再点击就会要求再次登录.
认识HTTP响应
HTTP响应格式
HTTP的响应和请求的都由四个部分组成
![](https://i-blog.csdnimg.cn/blog_migrate/85ba868a454d2e460a9a0be95b5825dc.png)
首行
响应头(header)
空行(表示header的结束标记)
正文(body)
但是里面的内容有所不同.
首行:
![](https://i-blog.csdnimg.cn/blog_migrate/3c6b7a0f43139a49feaa33ea13b6d35f.png)
状态码
HTTP状态码,它描述了此次响应的结果(成功,失败,原因...)
下面举一些常见的状态码:
200 OK 表示成功了
302 Move temporarily 表示重定向
重定向类似于电话号码的呼叫转移.
302这里的重定向表示临时重定向,301则是永久重定向
临时重定向需要服务器
在302这样的响应报文中,会在header里面带有一个 Location 属性,通过这个属性来描述要跳转到哪个新的网址.
![](https://i-blog.csdnimg.cn/blog_migrate/d0fa75b539fa5b9fbbf3bdee36fda097.png)
403 Forbidden 表示访问被拒绝(没有权限)
比如:码云上面的仓库设置私密和公开,私密仓库则他人没有权限访问
404 Not Found 表示访问的资源不存在
在服务器上没找到这个资源
500 Internal Server Error 服务器内部错误
比如:服务器代码抛异常了
504 Gateway Timeout 响应时间太久,浏览器等不及
除了上面这些之外还有很多的状态码,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/bd9e8e9d18a9e637c11f74d66ffeac16.png)
这些状态码可以被分为几个大类:
2xx 成功
3xx 重定向
4xx 客户端错误
5xx 服务器错误