一文详解CORS与预检请求

作者:大田稻谷 时间:2024-06-10 16:04:19 

CORS

出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。例如,XMLHttpRequest 和 Fetch API 遵循。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。

跨源资源共享CORS,通过允许服务器标示除了它自己以外的其他访问源、协议或端口,使得浏览器允许这些源访问加载自己的资源。简单讲,就是目标资源与当前页面不处于同一个域时,浏览器的同源策略会阻止请求发出者获得响应数据。除非服务器允许跨域访问,也就是支持CORS。

这是一些CORS相关的响应头信息,如果目标资源服务器支持CORS,必须附带一部分这些头信息与浏览器交互

Access-Control-Allow-Origin:该字段必须出现在服务器的响应中,表示允许跨域的源。如果是通配符( * ),表示接受任意域名的请求。
Access-Control-Allow-Methods:该字段表示接受的请求方法列表,多个值用逗号分隔。
Access-Control-Allow-Headers:该字段指定了实际请求可以携带的头部信息,多个值用逗号分隔。
Access-Control-Allow-Credentials:该字段标记是否允许发送 Cookie。如果为 true,则表示允许发送 Cookie。
Access-Control-Max-Age:该字段指定了预检请求的有效期(单位为秒),即在指定时间内不再发送预检请求,直接发送实际请求即可。
Access-Control-Expose-Headers:该字段用于指定哪些头部信息可以作为响应的一部分被获取到。

预检请求

当发送跨域请求时,浏览器会先发送一个OPTIONS方法的预检请求,探测服务器是否允许实际请求(POST、GET等)的跨域访问。服务器在接收到这个请求后,会返回一组响应头信息(详见上文),包含了对CORS的支持情况和允许的请求方法,如果服务器对跨域请求进行了允许,则浏览器才会真正地发送POST请求。如果服务器对预检请求的响应头中拒绝跨域访问或者根本没有任何CORS头信息,浏览器会抛出错误

因此,浏览器需要发送两次请求来确认服务器是否允许跨域请求,并确保安全性。

下面将演示触发预检请求的情况并且演示是处于跨域的环境下。

携带了自定义头信息的请求

在这种情况下,无论任何请求方法都会触发预检请求

我们请求 https://api.github.com/,这个接口支持跨域访问,我们通过添加自定义请求头,来触发预检请求

代码:

var requestOptions = {
 method: 'GET',
 headers: {
   test: 'test'   // 自定义的头信息
 },
 redirect: 'follow'
}
fetch("https://api.github.com/", requestOptions)
 .then(response => response.json())
 .then(result => console.log(result))
 .catch(error => console.log('error', error))

运行效果:

一文详解CORS与预检请求

可以看到明明在代码里面只有一次请求,可是浏览器却发出了两次请求,其中一个请求就是预检请求

看下预检请求和真实请求的请求头:

一文详解CORS与预检请求

一文详解CORS与预检请求

不难发现

  • 真实请求中,携带了自定义请求头字段

  • 在预检请求头中,access-control-request-headers字段标识了真实请求头中的自定义字段

  • 在预检请求头中,access-control-request-method字段标识了真实请求所使用的方法,这里是GET方法

总结来说,预检请求会携带上真实请求使用的请求方法和自定义头字段,去探测服务器是否允许这样做。

再来看下预检请求的响应头

一文详解CORS与预检请求

这些用蓝色方框圈起来的字段可以在上文中找到对应的解释。这里需要说明一点,可以从第一张图看到真实请求是失败的,原因在于我们添加的自定义请求头字段test并不在服务器允许的请求头字段中,这一点从预检请求的响应头字段access-control-allow-headers很容易看出。

那么如果不携带test头信息,或者换成允许的头字段,请求会成功,这一点留给读者自行测试。

PUT,DELETE方法的请求

PUT请求

var raw = JSON.stringify({
 "selected_organization_ids": [
   32,
   91
 ]
})
var requestOptions = {
 method: 'PUT',
 body: raw,
 redirect: 'follow'
}
fetch("https://api.github.com/enterprises//actions/runner-groups//organizations", requestOptions)
 .then(response => response.text())
 .then(result => console.log(result))
 .catch(error => console.log('error', error))

一文详解CORS与预检请求

DELETE请求

var requestOptions = {
 method: 'DELETE',
 redirect: 'follow'
}
fetch("https://api.github.com/admin/users//authorizations", requestOptions)
 .then(response => response.text())
 .then(result => console.log(result))
 .catch(error => console.log('error', error))

一文详解CORS与预检请求

真实请求失败是因为没有传递正确的参数或者接口需要认证。

服务器不允许跨域

上文的演示都是建立在目标资源允许跨域访问的基础上,下面演示目标资源不允许跨域的情况

fetch("https://buy.vmall.com/getSkuRushbuyInfo.json", {
 method: 'get',
 headers: {
   test: 'test'
 }
}).then(res => {
 return res.json()
}).then(res => {
 console.log(res)
})

一文详解CORS与预检请求

一文详解CORS与预检请求

观察到预检请求头中没有任何CORS响应头信息,表示服务器不允许跨域访问,这时候浏览器就会报错

一文详解CORS与预检请求

在代码层面也是可以捕捉到错误的,但是演示代码中没有捕获。

总结

  • CORS是一套规范,指导浏览器和服务器之间如何进行跨域资源共享

  • 如果请求跨域,对于一些特定类型的请求,浏览器会先发送一次预检请求,去探测服务器是否允许

  • 演示了一部分会触发预检请求的情况

来源:https://juejin.cn/post/7224903881729753148

标签:CORS,预检请求
0
投稿

猜你喜欢

  • python实现简单名片管理系统

    2023-06-13 08:03:12
  • Python md5与sha1加密算法用法分析

    2021-04-21 01:51:44
  • mysql创建Bitmap_Join_Indexes中的约束与索引

    2024-01-15 18:25:50
  • 教你如何在Pytorch中使用TensorBoard

    2022-02-22 17:55:46
  • python用700行代码实现http客户端

    2021-12-06 20:32:49
  • SQL Server导出表到EXCEL文件的存储过程

    2009-01-06 11:24:00
  • 浅析python 内置字符串处理函数的使用方法

    2021-07-17 09:23:09
  • 年底了,你的mysql密码安全吗

    2024-01-12 23:50:00
  • python 调用win32pai 操作cmd的方法

    2023-11-15 12:32:09
  • 解决IE6、IE7、Firefox兼容最简单的CSS Hack

    2007-10-14 10:51:00
  • 20分钟MySQL基础入门

    2024-01-22 21:37:54
  • 利用ASP.NET MVC和Bootstrap快速搭建响应式个人博客站(一)

    2023-07-06 23:47:39
  • selenium+python设置爬虫代理IP的方法

    2021-10-01 11:14:33
  • Python中生成器和yield语句的用法详解

    2022-06-04 16:56:19
  • MySQL如何实现负载均衡功能

    2024-01-20 20:25:45
  • Python 图像处理之PIL库详解用法

    2023-05-02 18:06:50
  • SQL Server模糊查询的常见方法总结

    2024-01-21 19:15:49
  • BeautifulSoup中find和find_all的使用详解

    2023-11-08 21:00:22
  • python实现超简单端口转发的方法

    2022-12-25 04:00:53
  • 如何使用python中的networkx来生成一个图

    2022-08-13 05:13:32
  • asp之家 网络编程 m.aspxhome.com