跨域请求是目前前端框架式发展中必须解决的问题,目前主流的浏览器均支持cors跨域请求,浏览器无需做过多的处理,在服务器端只需要设置Access-Control-Allow-Origin为*或者是或者是发起这个请求的页面的域名即可。但是IE浏览器只有在IE10及以上版本才支持。
在IE9和IE8浏览器中,I引入了 XDomainRequest 对象。XDomainRequest 对象允许 AJAX 应用程序在满足一定条件的时候,直接发起安全的跨域请求。这个条件是:当数据源指明 HTTP 响应是公共的,并且AJAX应用程序可以确保 HTTP 响应只被当前页面读取。在那种方式下,同源策略安全保证是受到保护的。服务器端也是需要设置Access-Control-Allow-Origin为*或者是或者是发起这个请求的页面的域名即可。
但是这种方式有很大的限制:
1. 必须使用 HTTP 或 HTTPS 协议访问目标 URL
这一条很简单——因为 XDomainRequest 对象依赖于一个HTTP响应头来实现访问控制,XDomainRequest 对象要求目标 URL 符合 HTTP 或 HTTPS 协议,以便于 XDomainRequest 对象检验响应头。检验响应头的目的是为了得到一个允许调用者访问 HTTP 响应的许可。所以,当开发者进行本地测试时需要将测试页面放到web容器中。
2.只能使用 HTTP 的 GET 方法和 POST 方法访问目标 URL
向服务器发送的请求只支持get和post两种方式。但是也基本上能满足我们的基本使用。
3.请求中不能加入自定义的报头
所有XDomainRequest对象发送的请求带有一个 Origin 请求头,显示调用页面的源(域名)。
4.只支持 text/plain 作为请求报头Content-Type的取值
为了应对这个问题,当服务器接收到来自XDomainRequest对象的请求的时候,当前处理HTML表单的服务器代码必须重写,来手动地把请求体解析成名-值对。这使得添加XDomainRequest对象的支持功能变得比原先困难得多。
5.身份验证和cookie不能和请求一起发送
为了阻止对用户的环境验证(比如cookies、HTTP身份验证、客户端证书等等)的误用,请求将会失去cookies和身份验证,并且将会忽略任何身份验证请求或HTTP响应中设置 cookies 的指令。
7.请求URL必须和主页URL采用相同的协议
发送请求的页面协议如果是http,则请求的接口也应该是http协议,如果请求的页面协议为https,则请求的接口也应该为https。
8.返回值没有没有 response status code
在返回值中直接就是返回的数据,不包含状态码等其他数据。
了解了XDomainRequest的一些限制之后,来写一个方法来实现它
function fetchIe9(url, options = {}){
if (window.XDomainRequest) {
return new Promise((resolve, reject) => {
const method = options.method || 'GET';
const timeout = options.timeout || 30000;
let data = options.body || options.params || {};
if (data instanceof Object) {
data = JSON.stringify(data);
}
const XDR = new XDomainRequest();
XDR.open(method, url);
XDR.timeout = timeout;
XDR.onload = () => {
try {
const json = JSON.parse(XDR.responseText);
return resolve(json.data);
} catch (e) {
reject(e);
}
return reject({});
};
// fix random aborting: https://cypressnorth.com/programming/internet-explorer-aborting-ajax-requests-fixed/
XDR.onprogress = () => {};
XDR.ontimeout = () => reject('XDomainRequest timeout');
XDR.onerror = () => reject('XDomainRequest error');
setTimeout(() => {
XDR.send(data);
}, 0);
});
} else {
// native fetch or polyfill fetch(XMLHttpRequest)
// fetch...
}
}