对于为什么要区分简单/预检请求的理解

这篇文章是在学习content-type的时候联想到的,为什么简单请求/非简单请求要区分不同的content-type,非常具体的就是那三种?依据是什么?

如何区分简单/非简单请求?

浏览器对跨域请求中的简单请求和非简单请求的处理是不一样的:

简单请求:

  • 方法:HEAD GET POST
  • 请求头不超过以下字段Accept、Accept-Language、Content-Language、Last-Event-ID、DPR、Downlink、Save-Data、Viewport-Width、Width、Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

非简单请求

不同时满足上述条件的请求就是非简单请求。浏览器对于非简单请求会进行一次预检请求。预检请求会将本次请求的请求方式、请求头和origin发送到服务器,询问服务器是否允许发送此次请求。

为什么要区分简单请求和非简单请求?

对于简单请求和非简单请求的这些限制有许多疑问,开始对于区分简单/非简单请求的原因理解如下:

服务器对于跨域请求通常会返回cors相关的响应头来告知浏览器是否允许此次跨域操作,但是对于一些直接能够修改或者新建服务器资源的请求,比如PUT DELETE 等请求,在没有返回响应之前就会对服务器资源造成损害。针对这种请求,浏览器需要首先进行一次预检请求,询问服务器是否允许此次请求,以达到保护服务器资源的目的。

后来,我开始纠结,content-type为multipart/form-data的post请求不是也会修改服务器资源吗?为什么将它划分为简单请求?

看了一篇文章,CORS 为什么要区分『简单请求』和『预检请求』?,发现事情可能没那么简单。

  • 划分简单/预检跨域请求的依据

传统的HTML form在不依赖脚本的情况下,通过POST、GET、HEAD请求,content-type可以设置text/plain、multipart/form-data和application/x-www-form-urlencoded三种,来发送跨域请求(url)。简单来说,浏览器对这些形式下的跨域请求做不了任何限制。

其他形式的请求是普通的form无法实现的,需要依赖脚本去添加一些自定义请求头或者form本身无法实现的方法(PUT等)

根据这个来区分简单/预检请求。

  • 为什么要对非简单跨域请求做预检?

原因有以下几点:

  1. 减少非简单跨域请求对服务器的影响(开始时就提到,服务器有时候不想理睬跨域请求),比如PUT、DELETE请求可以直接新建或者修改、删除服务器中的资源。预检请求可以防止该情况发生。

  2. 减少服务器对于是否跨域的计算量

对于非简单请求的跨域请求,服务器对于是否跨域的计算是在预检请求上,如果预检请求通过之后,正式请求都不用再次计算。而且一次预检请求通过后,之后的每次请求都只会发正式请求。节约了很多服务端的计算量。

  • 为什么不对简单的跨域请求做预检?

原因有以下几点:

  1. 一开始就提到,form能实现的简单跨域请求,浏览器做不了任何的限制。
  2. 没必要对简单请求做预检。比如,一些post请求只是想打个日志,并不需要服务器的响应,但是如果加预检请求,预检请求不通过就做不了这件事。还有一些GET请求、HEAD请求只是想获取资源,并不会修改资源,在不获取响应的时候并不会对服务器造成影响。在这种情况下,加预检请求,只会增加服务器的负担

为什么不区分表单跨域简单请求和非表单跨域简单请求?

最后,杠精(比如我)就会问了,既然一开始是因为form来区分两者的,那不如就按照表单跨域来区分一下:简单表单跨域请求和简单非表单跨域请求,绕晕了…,对于非表单简单跨域请求实行预检请求,怎么样,是不是完美无缺(微笑)…

原因如下:

  1. 这样划分之后,相当于服务器默认允许表单跨域请求。

  2. 对于其他非表单跨域简单请求进行预检也无必要,他们并不会对服务器造成不可想象的影响,还会麻烦服务器又要进行额外的预检响应。

  3. 服务器还要区分表单/非表单跨域请求,弄啥嘞!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享