你好!如果你翻到这里,我相信你可能遇到过:在做 API 借口调试时,浏览器 console 框莫名其妙地报出 CORS 相关的错误。今天,我们将会对这些错误是什么,并且如何解决这些错误进行探究。
我们的浏览器里边有一些安全策略,以保证数据传输的安全性,并且在传送抵达终端用户前,保证其不存在攻击数据的行为。现代浏览器具备的其中一项策略称为 same-origin policy(同源策略),也就是:在同源上的资源才能被网页端用户访问到。
首先让我们看看同源是什么
例如,我们有以下几个网站
:4000
这些网站不是同源的,因为它们有不一样的端口、协议、域名,而一个网站要想是同源的,它必须有相同的协议、域名和端口号。协议(例如 https http) 和 域名(例如 example.in 或者 exaple.com)。我们知道我们的网站运行在不同的端口上,但是端口号也需要一样(才能满足同源)。
现在浏览器工作原理是怎样的,让我们假设,你正在从源 :3000 请求,可是你的资源在源为exampleAPI.com/的服务上放着,那么你就会得到 CORS 报错,正是因为浏览器有同源策略,而你正在从不同的源请求(数据,图片等等)。
如何解决这些报错
通过(在所访问的)资源所在的服务端修改一些配置,错误就可得以解决。例如,你正在开发一个全栈 web 应用,前端使用的是 Reactjs,后端使用 Node JS 提供 APIs(Application Interfaces 应用接口)。现在,当你从客户端请求(数据),由于源不匹配,就出现了(跨域)错误。服务端需要在返回(response)中指定允许访问的源,浏览器才能察觉到,并不阻拦返回的数据,因而解决 CORS 错误。
不论后端使用使用的什么语言框架如,Django、Node 或者 C#,我们仅需要在服务端配置(server config)中添加允许(跨域)的源,这样服务端(server)会在返回体中发送一个特定的参数——Access-Control-Allow-Origin。
如图,我们可以看到,当使用 Access-Control-Allow-Origin : * 这个参数时,浏览器知道了允许访问这个资源的源,而 * 则表示任何源都可以访问这个资源。当然,我们也可以设置一个允许访问一些资源的源的数组。
这里有一些在 Node\Express 应用中跨域的代码片段,你需要使用命令行 npm install cors 安装 cors 包。
然后,你仅用执行 app.use() 然后传入 cors 函数进去。
这个 cors 函数接受一个对象作为参数,对象中你需要添加键值对:origin: *,你也可以指定一个允许(跨域)源的数组作为键值对的值。并不推荐使用 *,因为它允许所有源访问资源(如果都设置 * ,同源策略就无意义了),通常情况是提供一个列有允许访问源的数组。
预检请求(Preflight request)
CORS 预检请求是一个CORS请求,它用来检查 CORS 协议在服务端是否被支持浏览器工作原理是怎样的,服务端是否理解特定的(请求)方法和头部。
因此,便有了两种基本类型的请求
简单请求预检请求
使用如 GET、HEAD、POST 方法的请求是简单请求,因为这些请求没有在服务端产生副作用。通常情况下,GET 请求会从服务端获取数据,POST 请求会在服务端创建新的数据,但是他们都不会替换在服务端已经存在的数据。
使用如:DELETE 或者 PUT 方法的请求是预检请求,因为当使用这些方法时,任何人都可以修改或者删除已经存在服务端的数据,从而产生副作用,浏览器端在发送真实的请求前,它们会发生预检请求,并携带 access-control-allow-method 和 access-control-allow-headers,这些头部字段用来检查服务端是否允许使用这些方法,是否允许这些操作执行,如果服务端返回 200 状态,就表明预检请求验证通过,浏览器端菜开始发送真正的请求。
希望现在你对 CORS 已经有了更好的理解,并且能够解决这些跨域错误,继续加油!
译者注:
其实跨域的情况经常遇到,尤其是开发中,因为本地都是 localhost 的域名,而为了验证效果,要么专门搭建测试环境填入 mock 数据,另外常用的就是设置 Access-Control-Allow-Origin 实现跨域。
对于预检请求,作者其实说的有点片。简单请求和非简单请求并非仅靠请求方法就可以区分,大家可以去搜索“CORS 简单请求 非简单请求”,就可以看到比较详细的介绍。
其次理解为啥预检请求要先理解什么是副作用,这些含有副作用的操作会导致服务端现有的数据修改或者删除,操作风险高所以需要先执行预检请求,保证后续真实请求的可靠性。
版权声明
本文仅代表作者观点。
本文系作者授权发表,未经许可,不得转载。
发表评论