跨域请求分为两种,一种是简单跨域请求,另外一种是非简单跨域请求。非简单跨域请求在发出请求之前,浏览器会先发出一个 preflight 请求,即一个 OPTIONS 请求,用来验证服务器端是否允许该请求的访问。当 OPTIONS 请求成功时,才会继续发送真正的请求。否则请求将会在 OPTIONS 阶段便失败了,后续真正的请求也不会发出去。
当请求带上了特殊的请求头时,服务器端返回的 OPTIONS 请求的响应必须包含 Access-Control-Allow-Headers 响应头,并且该值包含请求所带上的特殊请求头的名称。这时候请求才会成功,否则会被浏览器拦截。
当请求使用了特殊的 HTTP 方法,服务器端返回的 OPTIONS 请求的响应必须包含 Access-Control-Allow-Methods 响应头,并且该值包含当前使用的 HTTP 方法。如果没有该响应头,或者当前使用的方法并不在其值里面,则请求会被浏览器拦截。
因为非简单请求每次完整请求一次资源实际上都会发出去两个请求,为了减少 OPTIONS 请求发出的次数,以便减少带宽浪费,服务器端可以配置 Access-Control-Max-Age 来指定浏览器可以在多长时间内对 OPTIONS 请求做缓存,使得一次请求成功后,下次请求相同的接口时不用再发出 OPTIONS 请求。
当跨域请求需要带上 cookie 等身份凭证时,需要手动开启 withCredentials 选项,并且服务器端需要配置 Access-Control-Allow-Credentials 的响应头,否则请求将不会带上任何身份凭证,或者当没有 Access-Control-Allow-Credentials 时请求会被浏览器拦截。
当请求有带上身份凭证时,服务器端除了需要配置 Access-Control-Allow-Credentials 响应头之外, Access-Control-Allow-Origin 响应头的值不能是通配符,必须是具体的某一个域名。否则会被浏览器拦截。
在以上 8 点当中,值得注意的是第 3 点和第 8 点。
OPTIONS 请求是一个比较容易被人忽略的一个关键点,有一些后端人员在编写接口的时候,往往只知道在接口的响应头里面写入 Access-Control-Allow-Origin ,而没有意识到 OPTIONS 请求的存在。特别是 OPTIONS 请求并不是每个跨域请求都会带上的,这就导致了有些人会有疑问,为什么明明我发出去的是 GET 请求,结果却是发出去了一个 OPTIONS 请求。而即使有对 OPTIONS 请求做跨域允许的话,那么也很容易因为缺少相应的 Access-Control-Allow-Headers 或 Access-Control-Allow-Methods 响应头导致请求仍然失败。
第 8 点也是一个非常重要的关键点。如果你有接口需要对多个不同域名的网站提供服务的话,那么你的接口就不能使用 cookie 等身份凭证了,毕竟 Access-Control-Allow-Origin 不能设置为通配符,限制了接口使用的对象。
彩蛋时间
前面提到了只有非简单请求才会触发 OPTIONS 请求,而满足简单请求也就只有那三个条件。但是事实并不是想象中的那么完美。
来源:【九爱网址导航www.fuzhukm.com】 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!