一文详解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))
运行效果:
可以看到明明在代码里面只有一次请求,可是浏览器却发出了两次请求,其中一个请求就是预检请求
看下预检请求和真实请求的请求头:
不难发现
真实请求中,携带了自定义请求头字段
在预检请求头中,
access-control-request-headers
字段标识了真实请求头中的自定义字段在预检请求头中,
access-control-request-method
字段标识了真实请求所使用的方法,这里是GET方法
总结来说,预检请求会携带上真实请求使用的请求方法和自定义头字段,去探测服务器是否允许这样做。
再来看下预检请求的响应头
这些用蓝色方框圈起来的字段可以在上文中找到对应的解释。这里需要说明一点,可以从第一张图看到真实请求是失败的,原因在于我们添加的自定义请求头字段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))
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))
真实请求失败是因为没有传递正确的参数或者接口需要认证。
服务器不允许跨域
上文的演示都是建立在目标资源允许跨域访问的基础上,下面演示目标资源不允许跨域的情况
fetch("https://buy.vmall.com/getSkuRushbuyInfo.json", {
method: 'get',
headers: {
test: 'test'
}
}).then(res => {
return res.json()
}).then(res => {
console.log(res)
})
观察到预检请求头中没有任何CORS响应头信息,表示服务器不允许跨域访问,这时候浏览器就会报错
在代码层面也是可以捕捉到错误的,但是演示代码中没有捕获。
总结
CORS是一套规范,指导浏览器和服务器之间如何进行跨域资源共享
如果请求跨域,对于一些特定类型的请求,浏览器会先发送一次预检请求,去探测服务器是否允许
演示了一部分会触发预检请求的情况
来源:https://juejin.cn/post/7224903881729753148


猜你喜欢
- 本文实例讲述了javascript insertAfter()定义与用法。分享给大家供大家参考,具体如下:HTML部分:<div id
- sql不常用函数总结以及事务,增加,删除触发器 distinct 删除重复行 declare @x 申明一个变量 convert(varch
- 今天用python实现了一下简单的聚类分析,顺便熟悉了numpy数组操作和绘图的一些技巧,在这里做个记录。from pylab import
- 1 算术运算add(other)比如进行数学运算加上具体的一个数字data['open'].add(1)2018-02-27
- css+div做的菜单:一个主显示层,别的列表都隐藏着,用js函数设置列表的显示和隐藏。分别用到了两个函数,函数实现的效果是一样的,一个是参
- 项目涉及的数据库表并不多,但每个select、insert、update和delete都去手动拼接字符串,是很低效的,尤其在时常要修改结构的
- csv文件CSV文件是最常用的一个文件存储方式。逗号分隔值(Common-Separated Values,CSV)文件以纯文本形式存储表格
- pytest的setup与teardown1)pytest提供了两套互相独立的setup 与 teardown和一对相对自由的setup与t
- 本文实例讲述了Python进程间通信Queue消息队列用法。分享给大家供大家参考,具体如下:进程间通信-QueueProcess之间有时需要
- 在main.js里进行全局注册 Vue.prototype.funcName = function (){}在所有组件里可调用this.fu
- 本文采用OpenCV3和Python3 来实现静态图片的人脸识别,采用的是Haar文件级联。 首先需要将OpenCV3源代码中找到data文
- CocosCreator版本:2.4.2jszip的实际项目应用游戏中有大量配置的情况下,文件会变得非常大,所以有些游戏会采用zip包压缩解
- #!#backup.sh##系统名称sysname=gzsyspath=/home/oracle/databak/$sysname/v_da
- 当我们的函数接收参数为任意个,或者不能确定参数个数时,我们,可以利用 * 来定义任意数目的参数,这个函数调用时,其所有不匹配的位置
- 五一在家写的,和大家分享,支持所有浏览器,添加了左侧菜单点击变色效果<!DOCTYPE html PUBLIC "-//W3
- 仿照微信朋友圈做了一个界面如下,先看效果:1、点开界面2、选择图片3、点击上传4、动态显示第一个页面的wxml:<view class
- code原文档 1.txt :HelloNanjing100实现代码:file_ = "1.txt"r_file = o
- 1、主动删除对象调用del 对象;程序运行结束后,python也会自动进行删除其他的对象。class Animal: &nbs
- 远程连接SQL Server 2008,服务器端和客户端配置关键设置:第一步(SQL2005、SQL2008):开始-->程序--&g
- 一、Python 操作 Excel 的常用库小伙伴你好,在开始操作 Excel 之前,你需要安装 Python 和一些相关库。可以使用 pi