HTTP请求方法的异同

HTTP请求方法的异同

HTTP(HyperText Transfer Protocol,超文本传输协议)中定义的请求方法共八种(GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE,参看RFC7231)。工作中我们最常接触到的是其中的 GET、POST、PUT 和 DELETE。网上有很多针对这四种方法的说明和比较,但内容都不尽如人意。为了能让大家更清晰地了解这些方法,在实际工作中灵活运用,我将从定义和实现两个方面详细地阐述一下它们的异同。

首先,看一些基本概念。超文本传输协议是网络七层结构中应用层的协议。我们看到“超文本”一般会联想到另一个词:HTML(HyperText Mark-up Language,超文本标记语言)。那什么是“超文本”?“超文本”是 1965 年美国人Ted Nelson 创造的,简单的说就是包含有其他文本链接的文本 (Hypertext is text which contains links to other texts),通过这些链接可以访问指向的文本。HTML 就是用来创建超文本(如 Web 页面)的。最初设计 HTTP 的目的是为了能够在客户端和服务器端之间传输超文本文档 (HTML)**。不过随着时代的发展,“超文本”已经从最初的纯文本扩展成为包括文本、图像、音频、视频等在内的多媒体。现今,把 HTTP 称为超媒体传输协议可能更为合适些**。

针对 HTTP,有文档明确定义的版本有 0.9(1991)、1.0(1996)、1.1(1997)和 2(2015)。目前使用最广泛的是 1.1,该规范由 IETF(Internet Engineering Task Force,互联网工程任务组)中的HTTP Working Group(HTTP 工作组)于 2014 年更新,定义的内容在 RFC7230–RFC7235 六个文档中。

接下来,开始正式的对比:

1 定义上

RFC 文档定义了三种方法属性:安全、幂等、可缓存。

安全

如果请求方法的语义是只读的(如 GET、HEAD、OPTIONS、TRACE ),那么该方法就是安全的。也就是说客户端不会请求和期望改变服务器上目标资源的任何状态。

幂等

如果使用该方法对服务器发送多次相同请求和一次请求的效果是一样的,那么该方法就被认为是幂等的。PUT, DELETE 及上面提到的安全方法都是幂等的。

可缓存

对于请求方法的响应被允许存储以备将来重用,那么该方法就可以定义为“可缓存”。一般来说,不依赖于当前响应的安全方法被定义为可缓存的。规范将 GET,HEAD 和 POST 定义为可缓存,尽管绝大多数缓存实现只支持 GET 和 HEAD。

属性 GET POST PUT DELETE
安全
幂等
可缓存
语义 检索信息(查) 创建或附加资源(增、改) 创建或替换资源(增、改) 删除资源(删)

⚠️ 以上的“是”,指的是定义中有明确要求的。“否”指的是没有明确要求,可做可不做的。

稍微解释下:

  • 安全:使用 GET 方法,不能修改服务器上的数据,而其它方法是可以的。
  • 幂等:同样是添加资源,使用 PUT 只能添加一条数据,无论执行多少次。而使用 POST 可以是执行一次就添加一条新数据。

补充:

  1. 所有通用的服务器必须支持 GET 和 HEAD 方法,其他方法是可选的。
    这和大部分的实现还算是比较吻合,因为一般的服务器是做网站用途的,在地址栏中访问对应的 URL 地址、图片引入、JS 文件引入、CSS 文件引入等都是发送的 GET 请求。

  2. 无论是 GET 还是 POST 都没有限制请求参数的长度和位置(URL 后还是消息体 message body 里)。

2 实现上

  1. GET 能被缓存,POST 很少能被缓存 。

  2. GET 和 POST 请求参数的位置不同,GET 请求的参数放在 URL 中(以?分割 URL 和传输数据,参数之间以&相连,如:login?name=zqc&password=zqc。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用 BASE64 编码,得出如:%E4%BD%A0%E5%A5%BD,其中%XX 中的 XX 为该符号以 16 进制表示的 ASCII),而 POST 请求的参数放在消息体中。

  3. 由于以上 2 的缘故,再加上有些服务器会记录和打印 GET 请求的地址,因此,POST 比 GET 相对安全一些。但是使用抓包工具的话,只要不加密,参数都能被轻而易举地获取。

  4. 华为手机浏览器不支持 PUT 方法,因此有些公司会规定添加和修改都使用 POST。

  5. GET 和 POST 请求参数的大小主要是由浏览器和 Web 服务器决定。以下是利用 node.js 做服务端进行的一系列测试(感谢 橘子君):

浏览器 请求类型 GET(Bytes) POST(Bytes)
IE11 地址栏 2047 --
ajax 81593 102400
IE11 地址栏 2047 --
ajax
Edge 地址栏 2083 --
ajax 81488 102400
Chrome 地址栏只粘贴 81550 --
粘贴加输入 如果超32791,则为:32791+一次性新输入个数 --
ajax 有可能是服务器端限制 81459 102400
python ajax 81825 102400

也就是说除了在地址栏中输入 URL 发送 GET 请求有明显的限制,而直接通过代码发送请求,Get(80K 左右)和 Post(100K)发送的数据大小相差不多

3 误区

  1. 一般认为 HTTP 请求方法与CRUD(Create, Read, Update, Delete)操作的对应关系如下:
    而实际上,除了 GET 和 DELETE 可以这样对应,POST 和 PUT 都可以作为增加或修改操作

    CRUD HTTP
    增加 POST
    查询 GET
    更新 PUT
    删除 DELETE
  2. GET 请求能够被保存在浏览器的浏览历史里面

    不准确!只有是在浏览器地址栏内输入的 URL 地址才可以在浏览器历史中查看。

  3. GET 参数是带在 URL 后面,传统 IE 中 URL 的最大可用长度为 2048 字符,其他浏览器对 URL 长度限制实现上有所不同,POST 请求无长度限制

不准确!上方已经写出了结论:除了在地址栏中输入 URL 发送 GET 请求有明显的限制,而直接通过代码发送请求,Get(80K 左右)和 Post(100K)发送的数据大小相差不多

最后,再看下 HTTP 状态码,简单易懂:

作者

天下布武

发布于

2020-04-26

更新于

2023-08-05

许可协议

CC BY-NC-SA 4.0

评论