CORS跨域带来的preflight request

Jenkins是一个自动化发布,持续集成的一个服务器。我们在做的就是通过http调起这个Jenkins配置好的Job,来执行自动化脚本以部署,升级目标机器上的软件。

Jenkins restful api 需要将带有用户名密码authorization的作为HTTP的header。而此时就报错了,报文如下图的样子:
CORS跨域带来的preflight request
CORS跨域带来的preflight request

而且很奇怪,是一个options请求而不是我写的post请求。这时候本文的主角CORS,preflight request就要需要解释一下了。CORS指的是当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 本来post是一个“简单请求”但是因为我需要带authorization的header,所以就变成了“复杂请求”,而复杂请求就需要先发送options请求来询问你的服务器,允不允许你发送本次请求。而这次options请求就叫 Preflight request。而preflight request会丢掉credentials信息(包括cookies和authorization)所以服务器就会返回403 Forbidden。

解决方法:因为是在发送请求的时候丢掉了credentials,所以我们可以在xmlhttprequest对象的withCredentials:true来手动声明。但是在angular4.4.6 不支持!好多angular的用户差点被逼疯了,在github的issue里抱怨。
CORS跨域带来的preflight request
CORS跨域带来的preflight request

所以如果想如愿以偿带上你的credentials,你有两种选择,放弃angular自带的http服务,自己封装http请求,或者用es7的fetch。或者起一个proxy代理,让代理转发你的请求,这样就成为从服务器调用,绕开了浏览器发送preflight的限制。

Angular的issuehttps://github.com/angular/angular/issues/15805