在面试中,GET和POST的区别也是面试官非常喜欢问的问题之一;很多童鞋也背的很熟了,GET不安全,POST安全等等,然而这些可能并不是面试官真正想听到的,那么GET和POST区别到底在哪呢?

  我们将从下面六个角度来具体剖析一下GET和POST的真正区别。

安全性角度

  一般认为POST在传输数据时更加的安全,因为GET传输时将在URL中显示参数,而POST的数据则放在了请求体(body),所以更安全。

  这种想法的由来多半是因为表单form数据提交时默认GET传输时会把表单中的字符拼接到URL后作为参数传送,POST传输表单数据会放在body中;当GET方式提交后会把提交的数据显示在URL上。

1
2
3
4
5
6
7
8
9
10
<!-- GET提交 -->
<form action="/api/test/get" method="get">
<input type="text" name="password">
<button type="submit">提交</button>
</form>
<!-- POST提交 -->
<form action="/api/test/post" method="post">
<input type="text" name="password">
<button type="submit">提交</button>
</form>

  两种方式提交后URL上的差别让人们觉得POST相对于GET更安全。

form-get-post

  然而安全性的说法存在着两个问题:

  1. 抓包后POST请求也是能看到请求体(body)中的数据
  2. HTTP规范并未规定说 GET 就不能在请求体(body)中传输数据

  既然HTTP规范没有规定,那么为什么就不能传呢?我试着用axios和jQuery来在GET请求体中加入数据,无一例外的失败了;既然框架靠不住那就直接用原生的吧:

1
2
3
4
5
6
7
8
9
10
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText)
}
}
xhr.open('GET', '/api/test/get', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
//发送请求
xhr.send('password=123');

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  我们通过express来接收一下传输的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//其他代码略
app.get('/api/test/get', function(req, res){
console.log(req.body, 'get body')
res.json({
code: 1,
type: 'get'
})
})
app.post('/api/test/post', function(req, res){
console.log(req.body, 'post body')
res.json({
code: 1,
type: 'post'
})
})

  正当我兴奋的准备接收数据时,现实狠狠的给了我一拳:

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

1
{} 'get body'

  浏览器并没有往请求体中存放数据,直接把send中传输的数据给丢弃了,那么GET的BODY中真的就不能放数据吗?

doubt

  答案自然是可以的,浏览器由于规范问题不会在GET的请求体中添加数据,那我们可以尝试一下通过Fiddler的Composer来添加:

fiddler_get

  这样我们就能在express中看到GET请求中的

1
{ password: 'fiddler_123456' } 'get body'

  既然GET也能在Body中添加数据,那么POST请求数据的安全性并不是面试官期望听到的回答。

数据量角度

  常见的GET和POST区别还有GET传输的数据比较少,POST传输数据多;在HTTP规范中并没有对URL的长度和传输的数据大小进行限制,但是在实际开发时,由于浏览器和服务器均对URL的长度进行了限制,因此表现出了GET传输数据少的缺点。在笔者的测试过程中,Chrome的URL长度限制比较好,基本能达到1mb的限制;而在IE11中4kb~5kb的时候浏览器就会自动将URL后的参数丢弃了。

  而对于POST请求,由于数据放在请求体中,虽然理论上不会受到限制,但是实际开发中各个服务器也会对POST的数据大小进行一定的限制;比如nginx默认上传图片的大小是2mb,图片超过2mb就会提示413 Request Entity Too Large

  因此不管GET还是POST,数据传输大小都会有限制,只是POST的传输大小相对于GET来说比较大;数据量大小也并不是面试官期望听到的回答。

缓存角度

  GET请求多是用来获取数据的,比如一件商品的信息、商品列表等,在一定时间内,商品的信息不会那么快的变化,因此它通常用于缓存。

  而POST请求多是用于将表单数据提交到服务端,比如修改姓名、修改密码等操作,需要浏览器必须发送请求到达服务器才能进行操作,因此POST请求不能被缓存。

cache

  从上图可以看出,我们同时将GET和POST请求在浏览器中多提交几次,会发现不管多少次提交,POST请求都是200;而GET请求第一次200,后面的请求会304进行缓存下来。

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

编码角度

  GET请求由于请求数据一般都是在URL上,所以GET一般都是URL编码;而POST请求由于请求参数的多样性,因此有多重编码方式;一般POST请求有application/x-www-form-urlencodedmultipart/form-dataapplication/json三种传输方式。

  multipart/form-data一般在上传文件的时候通过Html5的FormData新特性来构造上传表单对象会用到这种编码方式,通过FormData上传的请求类似这样:

formdata

  application/x-www-form-urlencoded是Form表单的默认提交方式,这种方式的好处就是浏览器都支持;但是缺点是在请求发送前需要对数据进行序列化处理,以键值对形式,例如:key1=value1&key2=value2的形式发送到服务器;如果使用jQuery的ajax方法,它内部已经对JSON格式的数据进行了序列化处理了;而使用axios默认使用application/json进行编码,或者自己通过原生Ajax请求就需要自己进行序列化。

  随着JSON规范越来越流行,并且浏览器支持程度比较好,application/json编码也越来越被更多的开发者使用;通过Content-Type告诉服务器主体内容是JSON格式的字符串,服务器端就会进行解析;这样的好处是前端人员不需要关心数据结构的复杂度,只要是标准的JSON格式就能提交成功。

幂等性角度

  初次看到幂等这个词很多童鞋都很陌生,我们首先来看一下幂等的定义:

在编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。

  HTTP的幂等是指无论调用多少次,无论调用一次还是一千次,都具有同样的副作用。GET请求用于获取资源,不管调用多少次接口,都不会影响返回的资源;因此我们说GET请求是幂等的

1
2
GET /list     # 获取列表
GET /detail/1 # 获取详情

  比如我们在获取列表数据或者获取详情数据,只是查询数据,不会影响到数据本身,也不会对资源产生副作用;因此我们认为它是幂等的。

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  这里有的小伙伴可能会提出疑问了,如果通过GET请求返回当前时间,那岂不是返回的结果每时每刻都不一样吗?怎么会幂等呢?

  注意,我们这里强调的是一次和N次对资源产生的副作用是相同的,而非单纯的比较结果相同。比如我们GET /news/1用来获取某个新闻,不管我们调用N次返回的都是新闻,没有产生副作用;但是新闻偶尔会更新,返回的结果可能不尽相同。

  而POST请求很明显是非幂等的,因为请求多次,都会产生不同的资源。比如在支付中,我们调用POST请求,虽然我们每次就支付一块钱,但是每次必然会产生不同的订单(如果是同一个订单相信你肯定要投诉的)

TCP角度

get会产生一个TCP数据包,POST会产生两个TCP数据包。

get会发送http header和data给服务端,服务端返回一个200,请求成功。

post会先发送http header给服务端,告诉服务端等一下会有数据过来,服务端返回100,告诉客户端我已经准备接收数据,post在发送一个data给服务端,服务端返回200,请求成功。

更多前端资料请关注作者公众号``【前端壹读】``。
PS:公众号接入了图灵机器人小壹,欢迎各位老铁来撩。

本文地址: http://xieyufei.com/2020/06/12/Diff-Get-Post.html