一步一步解决异步跨域请求CORS(跨域资源共享)报错
Access-Control-Allow-Origin
错误
Failed to load http://localhost:8081/request: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
原因
No 'Access-Control-Allow-Origin' header这基本是跨域请求遇到的第一个错误。浏览器基于同源政策,它会禁止AJAX发起非同源请求,其中同源包括三同:协议相同(如http),域名相同以及端口相同。
CORS则是允许浏览器向跨源服务器发起请求。这需要服务器端支持。
解决
解决跨域请求的第一个问题就是在响应的头信息加上Access-Control-Allow-Origin。
指定域名
Access-Control-Allow-Origin: http://www.example.com
允许所有域名访问
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials
错误场景
考虑下一个登陆功能,进入登录页面,我们向服务器请求验证码,验证码存放在session里。用户输入登录信息以及验证码发起异步跨域请求登录,你会发现,每次验证都是验证码不正确。
原因
查看下验证码的http和验证登陆的http请求的响应头信息Set-Cookie,你会发现两次请求的SessionId是不相同的。
CORS请求默认不发送Cookie和HTTP认证信息,如果我们想让CORS保持会话,我们需要服务器和浏览器端支持。
服务器端需要添加Access-Control-Allow-Credentials响应头信息:
Access-Control-Allow-Credentials: true
浏览器端需要在AJAX请求添加withCredentials属性:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
预检请求(preflight)
错误
Failed to load http://localhost:8081/auth.json: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
原因
非简单请求的CORS请求(包括PUT,DELETE或Content-Type类型是application/json),浏览器会在正式请求前,增加一次HTTP的OPTIONS查询请求,称为预检请求。预检请求目的是为了检查正式请求的域名,头信息以及HTTP 请求方法是否符合要求。预检请求失败则不会发起正式请求。
如上面的错误提示,content-type没有在被允许的头信息里。
解决
使用Access-Control-Allow-Headers添加允许的头信息,如content-type
Access-Control-Allow-Headers:content-type
对于多个需要被允许的头部,使用逗号隔开,如:
Access-Control-Allow-Headers:x-requested-with,content-type