当前位置: 首页 > 科技观察

浏览器跨域请求机制:CORS_0

时间:2023-03-21 22:36:31 科技观察

大家好,我是前端西瓜哥。由于同源策略(Cross-OriginPolicy)的存在,当浏览器向一个域名下的另一个域名发送Ajax请求时,返回的数据通常会被浏览器拦截,导致开发者无法获取到返回的数据结果。这里说“通常”是因为浏览器额外提供了一种机制,可以正常使用Ajax请求非同源域名接口,也就是我们接下来要讲的跨域资源共享(CORS,Cross-OriginResource共享)。CORS会在上图中的第三步发挥作用。简单来说,如果请求b.com的HTTP响应头域中的某些头域符合一定的规则,返回的数据就不会被浏览器截获,请求者就可以正常获取返回数据。简单请求和非简单请求是浏览器发出跨域请求的两种不同的请求方式。让我们来看看。如果满足以下所有条件,则为简单请求。请求方法是以下之一:GET、POST、HEAD。除了浏览器自动设置的字段(如Connection)外,只有请求头字段Accept、Accept-Language、Content-Language、Content-Type集合中的值可以手动设置。请求头字段的Content-Type是以下之一:text/plain、multipart/form-data、application/x-www-form-urlencoded。(还有一些比较琐碎的细节,比如脚本设置,具体浏览器,这里就不展开了,具体可以参考官方文档)你可能对这个规则的设计很感兴趣,其实它是为了向后兼容,兼容一些之前不用Ajax就可以发送的跨域请求,比如可以通过表单元素生成的请求。点击表单下的提交按钮,页面跳转,然后发送请求。这种写法很老套,因为会自动跳转到页面,无法获取返回的数据进行下一步操作,实际开发中基本不会用到CORS机制接下来,HTTP响应头域需要使用头域Access-Control-Allow-Origin,并将其值设置为:*:允许对任何域名进行跨域请求。:具体域名。这里不能提供多个域名,只能提供一个域名。这也无可厚非,防止黑客通过强制要求获取服务器设置的白名单域名。我们不应该透露太多信息。为实现跨域白名单功能,服务端需要根据请求头字段动态返回该字段的值。另外,如果请求中携带身份信息,即Cookie,则不能使用*,需要指定具体的域名。这样设置后,我们就可以正常获取其他域名接口返回的数据了。接下来,让我们看看非简单的请求。非简单请求不满足简单请求规定条件的请求为非简单请求。对于简单的请求,为了兼容性,浏览器会直接发送请求。但是对于非简单的请求就不需要兼容了,所以浏览器给它加了严格的复杂机制。在发出真正的请求之前,浏览器会先发送一个OPTION请求来探索路径。这个请求被称为预检请求(preflight)。浏览器发送的请求会额外带上以下请求头字段:Access-Control-Request-Method:该字段告诉服务器使用何种HTTP方法发起真正的跨域请求。Access-Control-Request-Headers:该字段通知服务器当前请求使用的header字段不符合简单请求规则,比如使用JSON结构作为数据格式,preflight请求会携带Access-Control-Request-Headers:content-type下面是服务器的回合。服务器获取到足够的请求者信息,就可以考虑是否允许跨域了。服务器的响应头字段可以携带如下字段:Access-Control-Allow-Origin:用法同上节简单请求描述。Access-Control-Allow-Methods:可以发送的请求方法。如POST、GET、OPTIONS。Access-Control-Allow-Headers:可以使用的header字段,如X-PINGOTHER,Content-TypeAccess-Control-Max-Age:86400:缓存的有效时长,单位秒,设置后即可在此期间内使用免于发送预检请求。浏览器本身预设了一个最大缓存时间,防止返回的缓存时间过长(比如几年)导致的安全问题。浏览器拿到这些字段后,会进行比较。如果不符合规则,则不会发送真正的跨域请求。如果没有,那么将发送一个真正的跨源请求。需要注意的是,真正的请求需要像简单请求一样提供Access-Control-Allow-Origin头域,否则仍然获取不到返回数据。最后CORS的真实形式是非简单请求。它不会立即发送真正的请求,而是发送一个额外的OPTION方法的预检请求,让服务器决定是否允许即将到来的请求。简单请求是向后兼容的折衷产物。它实际上是直接向目标发起真正的请求,但是如果响应头没有设置正确的Access-Control-Allow-Origin,浏览器可能会拦截返回的数据。