CORS简单请求和预检请求

客户端在请求 CORS 接口时,根据请求方式和请求头的不同,可以将 CORS 的请求分为两大类,分别是: 简单请求和预检请求

一、简单请求

同时满足以下两大条件的请求,就属于简单请求:  

请求方式:GET、POST、HEAD 三者之一  

请求头(仅包含安全的字段,常见的安全字段如下):

Accept
Accept-Language
Content-Language
DPR
Downlink
Save-Data
Viewport-Width
Width 
Content-Type
Content-Type:只有三个值(来自chatgpt4.0)
  1. application/x-www-form-urlencoded: 这是最常见的 POST 提交数据的方式。我们通过表单输入数据,提交表单,那么浏览器会把表单中的数据按照 key1=val1&key2=val2 的方式进行编码,然后发送给服务器。

  2. multipart/form-data: 这种类型主要用于上传文件。在浏览器中,multipart/form-data_encode方式往往结合着 form 的使用,它假设表单中的每个fields都是一部分,一般在上传文件的时候使用。

  3. text/plain: 文本格式。虽然这种格式在POST请求中很少见,但是在一个POST请求需要被发送为一个没被格式化的字符串形式的时候,这种Content-Type就派上用场了。

二、预检请求(看文章最后的图片)

只要符合以下任何一个条件的请求,都需要进行预检请求:  

  • 请求方式为 GET、POST、HEAD 之外的请求 Method 类型  
  • 请求头中包含自定义头部字段  
  • 向服务器发送了 application/json 格式的数据

在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。

服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

三、简单请求和预检请求的区别:

简单请求的特点:客户端与服务器之间只会发生一次请求。

预检请求的特点:客户端与服务器之间会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求。

四、简单请求过程:

当浏览器判定某个ajax跨域请求是简单请求时,会发生以下的事情

4.1请求头中会自动添加Origin字段

比如,在页面http://my.com/index.html中发起了以下跨域请求:

axios("http://crossdomain.com/api/news");

请求发出后,请求头会是下面的格式:

GET /api/news/ HTTP/1.1 Host: crossdomain.com

Connection: keep-alive 

Referer: http://my.com/index.html

Origin: http://my.com

Origin字段会告诉服务器,是哪个源地址在跨域请求

注意:如果使用file协议打开网页,则orgin为null

4.2服务器响应头中应包含Access-Control-Allow-Origin

当服务器收到请求后,如果允许该请求跨域访问,需要在响应头中添加

Access-Control-Allow-Origin字段。该字段的值可以是:

  • *:表示全部放行
  • 具体的源:比如http://my.com,表示我就允许你访问

假设服务器做出了以下的响应:

HTTP/1.1 200 OK Date: Tue, 21 Apr 2020 08:03:35 GMT 

Access-Control-Allow-Origin: http://my.com 

消息体中的数据 

当浏览器看到服务器允许自己访问后,于是,它就把响应顺利的交给js,以完成后续的操作。否则,你会就看到如下图片:

五、预检请求过程:

简单的请求对服务器的威胁不大,所以允许使用上述的简单交互即可完成。

如果浏览器不认为这是一种简单请求,就会按照下面的流程进行:

  1. 浏览器发送预检请求,询问服务器是否允许
  2. 服务器允许
  3. 浏览器发送真实请求
  4. 服务器完成真实的响应

比如,在页面http://my.com/index.html中有以下代码造成了跨域

axios("http://crossdomain.com/api/user",{ 
  method:"POST",
  headers:{// 设置请求头
     a: 1,
     b: 2,
     content-type: "application/json"
  },
   body: JSON.stringify({ name: "john", age: 20 })
});

浏览器发现它不是一个简单请求,则会按照下面的流程与服务器交互

5.1 浏览器发送预检请求,询问服务器是否允许

OPTIONS /api/user HTTP/1.1 Host: crossdomain.com

Origin: http://my.com

Access-Control-Request-Method: POST

Access-Control-Request-Headers: a, b, content-type

可以看出,这并非我们想要发出的真实请求,请求中不包含我们的响应头,也没有消息体

这是一个预检请求,它的目的是询问服务器,是否允许后续的真实请求。

预检请求没有请求体,它包含了后续真实请求要做的事情

预检请求有以下特征:

  • 请求方法为OPTIONS
  • 没有请求体
  • 请求头中包含

    • Origin:请求的源,和简单请求的含义一致
    • Access-Control-Request-Method:后续的真实请求将使用的请求方法
    • Access-Control-Request-Headers:后续的真实请求会改动的请求头

5.2服务器允许

服务器收到预检请求后,可以检查预检请求中包含的信息,如果允许这样的请求,需要响应下面的消息格式

HTTP/1.1 200 OK Date: Tue, 21 Apr 2020 08:03:35 GMT
Access-Control-Allow-Origin: http://my.com 
Access-Control-Allow-Methods: POST 
Access-Control-Allow-Headers: a, b, content-type 
Access-Control-Max-Age: 86400 

对于预检请求,不需要响应任何的消息体,只需要在响应头中添加: 

  • Access-Control-Allow-Origin:和简单请求一样,表示允许的源
  • Access-Control-Allow-Methods:表示允许的后续真实的请求方法
  • Access-Control-Allow-Headers:表示允许改动的请求头
  • Access-Control-Max-Age:告诉浏览器,多少秒内,对于同样的请求源、方法、头,都不需要再发送预检请求了

5.3浏览器发送真实请求

预检被服务器允许后,浏览器就会发送真实请求了,上面的代码会发生下面的请求数据

POST /api/user HTTP/1.1 Host: crossdomain.com 
Connection: keep-alive 
Referer: http://my.com/index.html 
Origin: http://my.com

{"name": "john", "age": 20 }

5.4 服务器响应真实请求

HTTP/1.1 200 OK Date: Tue, 21 Apr 2020 08:03:35 GMT 
Access-Control-Allow-Origin: http://my.com

可以看出,当完成预检之后,后续的处理与简单请求相同。下图为预检请求,请求过程图。

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值