文章目录
- HTTP请求/响应的基本结构
- 认识URL
- URL是什么和基本格式
- 关于encoding机制
- 认识方法(method)
- GET方法简介
- GET方法的特点
- POST方法简介
- POST方法的特点
- GET和POST的区别(经典面试题)
- 关于GET和POST的补充说明
- Restful风格
上节主要是对http协议的一些最基本的概念做出一些说明, 然后简单介绍了一下如何使用fiddler
进行对http请求的抓取, 本节我们更加细致的解释一下HTTP的报文格式相关的问题
HTTP请求/响应的基本结构
我们抓一个包来简单查看一下
请求的基本结构如下
我们的HTTP请求分为下面的几个部分
- 首行: 请求方法 + URL + 协议版本号
- 请求头(header): 由键值对组成的结构
- 空行: 作为header的结束标志, 分割请求头和正文
- 正文(body): 可以携带信息, 可有可无的存在
响应的基本结构如下
和请求类似, 也分为四个部分
- 首行: 协议版本号 + 状态码 + 状态码解释
- 响应头(header): 由键值对组成的结构
- 空行: 作为header的结束标志, 分割响应头和正文
- 正文: 可以携带信息
认识URL
URL是什么和基本格式
URL的全程是Uniform Resource Locator 统⼀资源定位符
, 描述了资源在网上的存在路径, 也就是说, 根据URL就可以找到某一个网络上的资源
URL的基本格式如下
协议方案名+(登录信息)+服务器地址(ip(域名)+端口号)
+带层次的文件路径+查询字符串(Quary String)+(片段标识符)
登录信息现在基本上不用了, 片段标识符用的也很少(文档类的网站还有)
我们拿访问leetcode平台的URL举例子
https://leetcode.cn/
我们访问的leetcode官网, 发现只有, 协议方案名+服务器地址(域名)
这说明URL中的好多内容都是可以省略的, 下面是URL中的内容以及是否可以省略
- 协议方案名: 明确了当前通信使用的协议, 可以省略, 省略后默认是
http://
- ip地址/域名: 描述了请求的服务器的ip地址(域名), 可以省略, 在html中
- 端口号: 描述了请求的服务器的目的端口, 可以省略, 省略之后相当于添加默认的端口号,
http->80, https->443
- 带层次的文件路径: 描述了请求的资源的更加具体的地址, 可以省略. 省略后相当于
/ .
- 查询字符串(Quary String): 使用键值对的格式进行存储, 详细的描述了请求的信息内容, 也可以传递一定的信息, 必要时使用
encoding
进行转码, 可以省略 - 片段标识符: 可以省略
我们在使用leetcode平台抓一个URL看看
我们搜索了一个 'N皇后'
https://leetcode.cn/search/?q=N%E7%9A%87%E5%90%8E
上面的URL中, 有 协议名称+域名(ip)+查询字符串(encoding转码了)
关于ip和域名的关系, 其实就是一回事, 因为ip地址不好被人们所记住使用, 所以想出来使用域名来代替ip地址, 二者通过一种叫做DNS
的应用层协议
进行连接, 值得注意的是
DNS
既是一种应用层协议, 也是一套服务器系统, 用来IP和域名之间的相互转换
我们想查询域名所对应的IP地址, 可以在cmd命令行
中使用ping
命令
ping + 域名
比如我们想查询 leetcode 平台域名对应的 ip 地址
关于空行的作用(这也是一个常见的面试题)
- 因为 HTTP 协议并没有规定报头部分的键值对有多少个. 空⾏就相当于是 “报头的结束标记”, 或者是"报头和正⽂之间的分隔符".
- HTTP 在传输层依赖 TCP 协议, TCP 是⾯向字节流的. 如果没有这个空⾏, 就会出现 “粘包问题”.
关于encoding机制
因为URL在定义的时候, 有一些特殊的字符, 可能会影响解析的过程
所以一旦涉及到一些特殊的字符, 那可能就需要进行转码encoding
操作, 即把转义的字符, 按照每个字节进行十六进制的转码, 然后在每一个字节前面加上%
.
发送到服务器之后, 再进行decoding
操作, 对转码的内容, 进行解码 从而可以找到对应的资源
但是发送到服务器之后, 进行decoding
的操作, 一般都省略了, 因为我们开发中经常使用的spring
系列的框架, 对这里的内容进行封装, 封装了解码的过程…
在浏览器上搜索C++
我们拿到上面的URL进行查看…
由于+
号是特殊字符, 所以此处进行了URL encoding
, 查询字符串中的C++
变成了C%2B%2B
因为+
对应的十六进制编码就是2B
, 除了这种特殊符号, 包括一些非英文的语言(比如中文), 表情包, 也会进行encoding
操作, 比如我们上面查询的N皇后
就是使用了转码操作…
我们给一个URL解码的网站
URL解码
我们尝试解码上面的leetcode上的查询内容, 就会发现, 其实就是N皇后…
认识方法(method)
上面我们说到, 在请求的首行里面, 格式是请求方法+URL+协议版本号
方法表示了这个请求的相关作用
不同的方法代表不同的含义, 但是最常见的只有四个GET
POST
PUT
DELETE
最常用的是 GET
和 POST
GET方法简介
GET方法的含义是, 获取某一种资源, 我们现在抓一个GET的请求看一看
尝试访问一个搜狗的网页
请求
响应
上面是使用GET请求获取到了一个网页的请求和响应
GET方法的特点
- 首行的第一部分是
GET
- URL的
Quary String
可以为空, 也可以不为空 - header部分有若干键值对结构
- body部分为空(也可以不为空)
GET
一般是幂等的…(一般情况)- body一般是空的, 如果需要给服务器发送一些数据, 可以通过
Quary String
进行传输
关于URL的长度问题
下面是引用的解释
关于 GET 请求的 URL ⻓度问题
⽹上有些资料上描述: get请求⻓度最多1024kb 这样的说法是错误的.
HTTP 协议由 RFC 2616 标准定义, 标准原⽂中明确说明: “Hypertext Transfer Protocol – HTTP/1.1,”
does not specify any requirement for URL length.
没有对 URL 的⻓度有任何的限制.
实际 URL 的⻓度取决于浏览器的实现和 HTTP 服务器端的实现. 在浏览器端, 不同的浏览器最⼤⻓度
是不同的, 但是现代浏览器⽀持的⻓度⼀般都很⻓; 在服务器端, ⼀般这个⻓度是可以配置的.
简单点说, 早期的浏览器版本不支持非常长的URL长度, 但是现在的URL以及完全没有长度的限制了…
关于为什么通常情况下GET方法设置为幂等的问题
幂等的含义就是, 同一个请求获取到的数据是相同的, 由于我们从服务器端获取到的数据, 通常情况下是相同的, 所以设置为幂等之后,
我们的本地就会缓存从服务器加载过来的数据, 从而在下次加载相同的内容的时候, 直接加载缓存到本地的资源就可以了, 从而加速了访问的速度, 传输层面的话, 也可以通过访问CDN服务器来加快访问服务器的过程(本质上是一种分布式存储机制)
如果真的想从新获取一遍资源, 就使用 ctrl + F5 强刷一下
但是随着互联网技术的进步, 很多时候, GET请求通常不设置为幂等的, 因为我们通常需要你的个性化推送
这就意味着不能设置为幂等的…
POST方法简介
POST的语义是传输某一种数据信息, 通常使用body
部分进行数据的传输, 关于POST最常见的场景就是, 登录, 上传
我们尝试抓取一个POST的信息来看一看
请求
响应
POST方法的特点
- 首行的第一部分是
POST
- URL的
Quary String
一般为空(也可以不为空) header
部分有多个键值对结构body
部分一般不为空, 通过body
来向服务器端传递信息
GET和POST的区别(经典面试题)
请你说说 GET
和 POST
的区别是什么
- 语义不同:
GET
表示从服务器端获取一些资源,POST
表示向服务器端提交一些资源 body
和Quary String
部分的不同
GET
请求的body部分通常为空(也可以不为空),POST
的body部分通常不为空(也可以为空)
GET
请求的Quary String通常不为空(也可以为空),POST
的Quary String通常为空(也可以不为空)- 传递数据方式的不同
GET
通过Quary String中的内容传递数据信息,POST
通过body传递数据信息 - 是否幂等(上面GET那里有解释)
GET
请求一般是幂等的,POST
请求一般是不幂等的 - 是否可以被缓存(和幂等相关)
GET
请求可以被缓存,POST
请求不能被缓存
关于GET和POST的补充说明
-
关于语义
GET
完全可以上传资源(通过Quary String),POST
方法也可以获取资源(通过body), 所以在实际的开发中, 两个方法的使用并没有明确的界限 -
关于幂等性
GET
的官方文档建议设置为幂等的, 但是我们实际的开发中也可以根据自己的需求进行开发, 比如主流的网站都有猜你喜欢
功能… -
关于安全性
有些资料说,GET
不如POST
安全, 这实际上是不合理的, 比如在登录的场景, 他的意思其实是, 如果使用GET
进行传输, 密码信息会直接显示到浏览器的上面的地址栏, 所以不安全, 这显然是一种掩耳盗铃的说法…即使你通过POST
传输, 我抓一个包也就全知道了, 所以POST
也不是很安全, 我们正确的加密传输的方案是在业务层直接进行加密(HTTPS只能保证传输过程中是安全的) -
关于传输数据量
有些资料说,GET
传输的数据量不如POST
多, 这实质上也是不严谨的, 我们现在的官方标准, 并没有规定GET
中URL
的长度, 也没有规定POST
中的body长度, 传输的数据量多少, 完全取决于不同浏览器和服务器的实现, 所以不能简单的说谁比谁传输数据少 -
关于传输资源类型
有的资料说,GET
只能传输文本数据,POST
不仅可以传输文本还可以传输二进制数据, 确实,GET
中的URL
中的Quary String
只能是文本数据, 但是我们要想实现传输二进制的效果, 可以对二进制数据进行URL encoding
操作转换为文本数据, 然后传输之后再进行decoding
操作进行解码即可
Restful风格
尽管我们的方法之间并没有明确的界限, 但是我们还是遵循一套大致的流程, 分别CRUD
操作
- POST: 新增
- DELETE: 删除
- GET: 查询
- PUT: 修改
在实际的开发中, 我们也可以尽量的遵循这种Restful
设计风格来实现代码…