文章目录
- 前言
 - 一、协议格式总结
 - 二、认识URL
 - 三、认识"方法"(method)
 - 1.GET
 - GET请求的特点
 
- 2.POST
 - POST 请求的特点
 
- 总结
 
前言
网络技术中,最核心的概念,就是"协议",HTTP就是应用层典型的协议
 应用层,很多时候需要程序员自定义应用层协议,也有一些现成的协议,供我们直接使用~
HTTP就是其中的"佼佼者"
- 浏览器和服务器的交互(打开网页)大概率就是HTTP协议
 - 手机APP喝服务器之间的交互,也大概率都是HTTP协议
 - 服务器之间的相互调用,也可以使用HTTP
 
最新的版本是HTTP 3.0,但是当前最常见的版本,还是HTTP1.1,以下也主要介绍1.1版本
在浏览器中输入一个"网址",稍等片刻就看到了网页,这个过程中,就是通过HTTP和服务器进行了交互~
 

HTTP这个协议,是属于最典型的"一问一答"模型的协议
学习HTTP协议,主要学习的内容,就是HTTP报文格式~
 报文格式就描述了一个HTTP请求是啥样的,以及相应是啥样的~

此处需要使用"抓包工具"来捕获请求交互的详细情况~~
“抓包工具"是个特殊的软件,相当于一个"代理程序”,浏览器给服务器发的请求就会经过这个代理程序,进一步就能分析出请求和响应的结果如何~
代理:找个人跑腿~
我和老板进行了哪些交易,这个时候,跑腿(代理)是非常清楚的~
作为程序员,通过代理,就可以知道浏览器和服务器之间具体的交互细节了~
谈到代理,代理,还分两种:
- 正向代理(给客户端提供服务的,和客户端关系紧密),站在服务器的角度,正向代理把真实的客户端给隐藏起来了,服务器不知道真实的客户端是啥
 - 反向代理(给服务器提供服务的,和服务器关系紧密),站在客户端的角度,反向代理把真实的服务器给隐藏起来了,客户端不知道真实的服务器是啥
 
使用抓包工具,来分析HTTP协议的工作过程~
 抓包工具有很多,我使用的是fiddler(其他的一些,wireshark,Charles,chrome的开发者工具等等…也可以)
简单介绍Fiddler:
左侧区域是抓到的请求 列表
双击左侧某个你想关注的请求详情,就会在右侧窗口显示出请求的具体情况
点击右上角的
raw标签页,显示HTTP请求最原始的样子点击右下角的
raw标签页,HTTP响应的最原始的样子由于响应数据,可能体积较大,服务器通常会返回一个"压缩"后的结果
小tips:如果抓不到很多请求的解决办法:
- 需要开启fiddler抓取HTTPS的功能!! 现在互联网上纯HTTP很少了,更多的是HTTPS,HTTPS可以理解成升级版本的HTTP,在HTTP的基础上,加了个加密层
 
- 如果开启了上述HTTPS也安装了根证书,还是抓不到~ 检查电脑上是否安装了其他的代理程序/代理作用的浏览器插件,fq工具/游戏加速器/steam++,本质上都是代理,这些程序都会和fiddler打架,无法同时运行!!
 
使用fiddler务必要把其他的代理程序关闭/禁用~
一、协议格式总结

 对照着抓包结果看一下请求情况:
GET https://www.sogou.com/ HTTP/1.1
Host: www.sogou.com
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://cn.bing.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: SUID=DCD4D38BD352A00A0000000062FB75D6; usid=2EC2C871ED18A00A000000006354C27B; SUV=1667727332968362; browerV=3; osV=1; IPLOC=CN6100; ABTEST=0|1668496465|v17; SNUID=7C6D0FB866638A1B7CD61A0F67F3B218; ld=pyllllllll20t8ezlllllp285VolllllTLkapZllll9lllllRZlll5@@@@@@@@@@; LSTMV=297%2C26; LCLKINT=6081
 
以上是一个完整的HTTP请求的样子~
 要构造一个HTTP请求,本质上就是往一个TCP socket中,按照下列格式来写入数据即可~
HTTP是一个文本格式的协议
-  
首行:

 -  
请求头
header 
Host: www.sogou.com
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://cn.bing.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: SUID=DCD4D38BD352A00A0000000062FB75D6; usid=2EC2C871ED18A00A000000006354C27B; SUV=1667727332968362; browerV=3; osV=1; 
 
这里是一个按行组织的键值对,每一行,是一个键值对,键和值之间使用 : 空格 来分割
 这里的键都是有固定含义的~
-  
空行
一个HTTP请求的header可以有若干个,就使用空行作为header的结束标记,类似于链表的null -  
正文
body
有的请求有,有的没有,承载一些具体的数据,可能是json格式的,也可能是其他格式的 
{"SessionId": "E25091DB353ABD99281B8635D8A845C8","AppId": "Edge_Win32","Language1": "zh-CN","Content": [{"TileId": "en-US","RevisionId": "0","TileElements": [{"LanguageId": "en-US","Text": "3. 空行","TextUnit": 8}]}],"Descriptors":[{"Name": "FlightIds","Value": "wac-wordeditorservicemultiplegrammarcritiquesperse1nce-treatment"},{"Name": "LicenseType","Value": "NoLicense"}]}
 

完整的HTTP响应的格式~
-  
首行

 -  
响应报头
header同样也是键值对的结构~ 
Server: nginx
Date: Wed, 16 Nov 2022 07:49:53 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: black_passportid=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=.sogou.com
Pragma: No-cache
Cache-Control: max-age=0
Expires: Wed, 16 Nov 2022 07:49:53 GMT
UUID: 8bce19ac-2795-40e5-a59e-f59e38db5c66
Content-Length: 14927
 
- 空行
作为header的结束标记~ - 正文
正文可以是json数据,可以是html,也可以是cmd 等等… 

接下来介绍HTTP协议中的细节~
二、认识URL
URL : 唯一资源定位符(用这个来找到网络上的资源)
 URI : 唯一资源标识符(用这个来区分一个网络上的资源)
 这俩概念非常相似,很多时候,并不会显式区分~
URL 里面是啥样子的,是有"RFC标准文档"来进行描述的~
RFC标准文档: 描述了很多网络中的协议标准,包括IP,TCP,UDP,HTTP …

 URL重要的部分:
- IP地址地址+端口号[基础]
 - 带层次的路径[开发中常用]
 - 查询字符串[开发中常用]
 
🎐URL encode / decode :
URL中已经包含了一些特殊含义的付好了,比如 :
/ ? @ ....
万一query string的value中,也包含了这些特殊符号会咋样?
很可能会有问题!! (浏览器可能会错误的识别URL,服务器也可能会错误的解析URL)
非常类似于编程语言里的变量名不能是"关键字"
URL encode / decode本质上就是把特殊符号进行转义了,这里转义的范围不仅仅是这些特殊符号,还有汉字~
转义规则:把待转义的字符串,把每个字符的十六进制表示前加上个%
把原始的字符,转成转义后的字符 =>
URL encode(编码)
把转义后的字符还原成原始的字符 =>URL decode(解码)
三、认识"方法"(method)
HTTP中非常重要的部分~
 可以把 方法 理解成 -> 你这个请求想干啥
- GET
 - POST
 熟悉了GET POST 就可以应对90%以上的场景了
1.GET
最常用的的HTTP请求方法~
- 浏览器地址栏直接输入
URL,此时就会触发GET html里面的link,a,img,script也会触发GET请求
href/src都会引入一个外部的资源~
本质上就是浏览器会重新发送一个GET请求,来从服务器拿到对应的数据~
一个浏览器加载出一个页面,往往要经过多重HTTP请求的交互~
比如搜索引擎会一次搜索出很多结果!
浏览器缓存:
浏览器在加载页面的时候,往往要加载这个页面依赖的很多资源,css,图片,js等…加载这些资源,显然是需要消耗不少时间的~为了提高页面加载效率,浏览器就会对加载过的这些
css图片,js进行缓存(保存在你本地的磁盘上)下次再访问同一个网页,之前的css,图片,js就不必重新从网络加载,而是直接读硬盘即可~
使用ctrl+f5强制刷新,就可以让浏览器不走缓存,直接强制从网络上获取资源~~
form表单html里form标签,可以构造出GET请求ajax(后面在"如何构造HTTP请求"中讲)
GET请求的特点
GET https://www.sogou.com/ HTTP/1.1
Host: www.sogou.com
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: SUID=DCD4D38BD352A00A0000000062FB75D6; usid=2EC2C871ED18A00A000000006354C27B; SUV=1667727332968362; browerV=3; osV=1; IPLOC=CN6100; ABTEST=0|1668496465|v17; SNUID=7C6D0FB866638A1B7CD61A0F67F3B218; ld=pyllllllll20t8ezlllllp285VolllllTLkapZllll9lllllRZlll5@@@@@@@@@@; LSTMV=297%2C26; LCLKINT=6081
 
- 首行的第一部分为 
GET URL的query string可以为空, 也可以不为空.header部分有若干个键值对结构.body部分为空
如果需要给服务器传递一些参数,这些参数通常就是通过querystring来传过去的
2.POST
产生POST途径
- form
 - ajax
 
POST 请求的特点
POST请求:
POST https://edu.bitejiuyeke.com/tms/login HTTP/1.1
Host: edu.bitejiuyeke.com
Connection: keep-alive
Content-Length: 117
sec-ch-ua: "Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42
Access-Control-Allow-Methods: PUT,POST,GET,DELETE,OPTIONS
Content-Type: application/json;charset=UTF-8
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Access-Control-Allow-Headers: Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild
sec-ch-ua-platform: "Windows"
Origin: https://edu.bitejiuyeke.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://edu.bitejiuyeke.com/login
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
{"username":"xxxxxxxxxxx","password":"xxxxxxx","uuid":"6cda4adb156c4f8ebe13263f069aa0e3","status":0}
 
- 方法叫做
POST url通常是没有query string的- 也是有若干
header,键值对的形式 body这里通常是有的~ (body的数据格式有很多种)
POST在传递信息给服务器的时候,通常就会把信息放到body中~

GET 和POST 的区别[经典面试题]
第一步,先盖棺定论:GET和POST没有本质区别,使用GET实现的场景基本都可以使用POST代替,使用POST实现的场景,也可以用GET来代替
第二步,再来谈细节上的区别~
GET的语义,是从"服务器获取个数据",POST的语义,是"往服务器上提交个数据"(这里是建议你设计的时候采取这样的语义~ )- 使用习惯上,给服务器传递的数据,
 GET通常是放在url的query string中,POST通常是放在body中(GET能否把数据放在body里? 也是可以的,不过很少见,浏览器不一定能支持,其他的http客户端是可以支持的,POST能否把数据放在query string里? 完全可以~但是也少见,浏览器啥的都是支持的)GET请求建议实现成"幂等"的!!POST一般则不要求实现成"幂等"(输入是确定的,输出结果也就是确定的),设置服务器的时候,就需要提供一些"接口/api",api传入的参数,就视为是输入,api返回的结果,就视为是输出,基于GET的api一般会建议设置成幂等的,基于POST的api则无要求,但也只是建议- 在幂等的基础上,
 GET的请求结果是可以被缓存的,POST则一般不会缓存(浏览器默认的行为,如果GET确实是幂等的,就不必处理,就让浏览器缓存,如果当前GET不是幂等的,就需要通过特殊技巧避免浏览器产生缓存 [典型的技巧就是让每次GET请求的url都不相同,通过特殊的 query string 来保证url不同])
总结























