cors跨域问题?

285 阅读3分钟

记一次cors预检不通过造成的原因:

这个报错是后端没有响应头没有返回Assess-Control-Allow-Origin字段;

名称

cors 资源共享,cross origin resource sharing。

功能概述

对于内些可能对服务器数据产生副作用的请求, 会先发起一个options的预检请求(preflight request)判断是否允许进行跨域,服务器确认允许之后,才会发起真正的http请求

场景

请求分为简单请求和非简单请求

简单请求

同时满足两大条件是简单请求

条件一:请求方法

  1. HEAD
  2. POST
  3. GET

条件二:请求头字段不超出以下字段

  1. Accept :指定返回类型,text/plain(纯文本)、text/html(html类型)
  2. Accept-Language 指定语言
  3. Content-Language 指定内容语言
  4. Last-Event-ID
  5. content-type:指定三个字段
  • text/plain 纯文本
  • multiple/form-data 上传表单内包含文件
  • application/x-www-form-urlencoded 对发送内容进行编码

简单请求包含origin字段(http会默认携带在Request header),代表访问的域名来源

Origin: http://api.bob.com
Host: api.alice.cÏom
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

若服务器检索后发现不在请求范围内,返回一个正常的http响应,但不包含Assess-Control-allow-Origin字段。如果在允许范围内响应头如下:

Access-Control-Allow-Origin: http://api.bob.com 允许访问域名,或者*不限制访问
Access-Control-Expose-Headers:yy  
Access-Control-Allow-Credentials:true 表示是否可以发送cookie
Content-Type:text/plain(纯文本内容); charset=utf-8

Access-Control-Expose-Headers:yy

这个字段代表可以从XMLHttpRequest对象的getResponseRequest拿到指定字段的值,亦可用getAllResponseHeaders拿到所有可读字段,如果多个用;分开。否则只能拿到指定的六个字段:content-language、content-type、cache-control、expires、last-modified、pragma

如果想发送cookie是需要服务端和客户端配合的

服务端
Assess-Control-Allow-Credentials:true
客户端:
const xhr = new XMLHttpRequest()
xhr.withCredentials =true;
如果省略withCredentials有的浏览器还是会发送cookie
xhr.withCredentials = false;

简单请求客户端只需发送origin字段后端会进行检索,就可以完成cors跨域请求。

非简单请求

触发非简单请求是不满足简单请求的条件一和条件二。

后端会进行预检请求校验,根据 Assess-Control-Allow-Origin 、Assess-Control-Allow-Method、Assess-Control-Allow-Headers

如果请求不通过就会抛出错误,js是捕捉不到的需要从console里面看。如果OPTIONS请求通过就会和简单请求一样。

总结:

  1. cors 是资源共享一种解决方案,但是不支持ie10以下
  2. cors请求分为简单请求和非简单请求
  3. 简单请求主要通过origin和Assess-Control-Allow-Origin进行校验
  4. 非简单请求是有触发条件的会根据三个字段进行校验
  5. 回归最开始的问题,根据报错发现没有对Assess-Control-Allow-Origin进行配置,那么好去找后端进行配置。