Open CntChen opened 6 years ago
Chrome: You will die! IE9: Not today!
搭建公司官网的框架时采用了 vuejs, 使用 history router mode 来做 SEO 优化, 使用 fetch 做网络请求, fetch 用 whatwg-fetch 做 polyfill. 根据百度浏览器市场份额统计, 2017年全年 IE9 的占有率达到 9.50%, 并且 vue 框架也是兼容到 IE9, 所以项目要求兼容到 IE9.
但是 fetch polyfill 并不兼容 IE9, 这篇文章追溯问题原因并提出解决方法.
在 IE9 下打开页面, 发现 fetch 请求报了Unhandled promise rejectionError: 拒绝访问:
Unhandled promise rejectionError: 拒绝访问
IE9
IE11 开 IE9 调试模式
怀疑是 fetch 的兼容问题, 查看一下版本:
$npm list whatwg-fetch project └── whatwg-fetch@2.0.3
查看了一下whatwg-fetch 兼容性: 只支持到 IE10. 然后看到 whatwg-fetchv0.11 可以兼容 IE9, 那就降级一下吧:
$ npm uninstall whatwg-fetch removed 1 package in 4.851s $ npm install whatwg-fetch@0.11 + whatwg-fetch@0.11.1 added 1 package in 5.96s
再试一下, 发现还是一样的问题.
XMLHttpRequest
fetch 的 polyfill 采用了 XMLHttpRequest 实现, 但是在 IE9 下面, XMLHttpRequest 是不支持跨域请求的. IE10 的 XMLHttpRequest 支持跨域, 而 IE8, IE9 需要使用 XDomainRequest 来实现跨域.
那就用 XDomainRequest 实现异步请求, 代码:
XDomainRequest
function fetchIe9(url, options = {}) => { if (window.XDomainRequest) { // https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest // only support GET and POST method // request and response content type should be JSON // without response status code 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({}); }; XDR.ontimeout = () => reject('XDomainRequest timeout'); XDR.onerror = () => reject('XDomainRequest error'); XDR.send(data); }); } else { // native fetch or polyfill fetch(XMLHttpRequest) // fetch... } }
需要注意的是:
responseType
题外话: whatwg-fetch 一直采用 XMLHttpRequest 来做 polyfill, whatwg-fetch1.0+ 不支持 IE9, 并不是因为没有采用 XDomainRequest, 而是因为 [IE9 的状态码不符合 fetch 规范][IE9 的状态码不符合 fetch 规范], 而 polyfill 的目标是 polyfill 规范, 而不是做兼容.
whatwg-fetch
whatwg-fetch1.0+
写好了代码, 在 IE9 中, 网络请求非常诡异, 经常不行: 请求只持续了不到 1ms, 并且接收数据为 0B, 没有状态码; 但是在少数时候是可以成功请求并获取数据的.
IE11 开 E9 调试模式 此时 IE11 的 IE9 调试模式是可以的, 看来模拟器还是模拟不到位.
查了好久, 终于看到一篇文章: Internet Explorer Aborting AJAX Requests : FIXED
IE timing out the request even though data is being transmitted.
主要的原因大概是 IE9 会将一个正在传输的请求 timeout 掉.
解决办法是:
onprogress
function fetchIe9(url, options = {}) => { if (window.XDomainRequest) { // https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest // only support GET and POST method // request and response content type should be JSON // without response status code 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... } }
https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
XDomainRequest – Restrictions, Limitations and Workarounds
https://blogs.msdn.microsoft.com/ieinternals/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds/
Internet Explorer Aborting AJAX Requests : FIXED
https://cypressnorth.com/programming/internet-explorer-aborting-ajax-requests-fixed/
不行啊,我这边还是报403
我们也是,前端换成XDomainRequest支持跨域后,就报403了
IE9 跨域请求兼容
背景
搭建公司官网的框架时采用了 vuejs, 使用 history router mode 来做 SEO 优化, 使用 fetch 做网络请求, fetch 用 whatwg-fetch 做 polyfill. 根据百度浏览器市场份额统计, 2017年全年 IE9 的占有率达到 9.50%, 并且 vue 框架也是兼容到 IE9, 所以项目要求兼容到 IE9.
但是 fetch polyfill 并不兼容 IE9, 这篇文章追溯问题原因并提出解决方法.
问题: 访问拒绝
在 IE9 下打开页面, 发现 fetch 请求报了
Unhandled promise rejectionError: 拒绝访问
:IE9
IE11 开 IE9 调试模式
怀疑是 fetch 的兼容问题, 查看一下版本:
查看了一下whatwg-fetch 兼容性: 只支持到 IE10. 然后看到 whatwg-fetchv0.11 可以兼容 IE9, 那就降级一下吧:
再试一下, 发现还是一样的问题.
问题原因: IE9
XMLHttpRequest
不支持 CORSfetch 的 polyfill 采用了 XMLHttpRequest 实现, 但是在 IE9 下面, XMLHttpRequest 是不支持跨域请求的. IE10 的
XMLHttpRequest
支持跨域, 而 IE8, IE9 需要使用 XDomainRequest 来实现跨域.那就用
XDomainRequest
实现异步请求, 代码:需要注意的是:
XDomainRequest
只支持 GET 和 POST mehtodXDomainRequest
不支持带 cookieXDomainRequest
不能设置responseType
, 通信双方需要约定数据格式XDomainRequest
的响应没有 response status code题外话:
whatwg-fetch
一直采用XMLHttpRequest
来做 polyfill,whatwg-fetch1.0+
不支持 IE9, 并不是因为没有采用XDomainRequest
, 而是因为 [IE9 的状态码不符合 fetch 规范][IE9 的状态码不符合 fetch 规范], 而 polyfill 的目标是 polyfill 规范, 而不是做兼容.问题: 请求异常终止和挂起
写好了代码, 在 IE9 中, 网络请求非常诡异, 经常不行: 请求只持续了不到 1ms, 并且接收数据为 0B, 没有状态码; 但是在少数时候是可以成功请求并获取数据的.
IE9
IE11 开 E9 调试模式 此时 IE11 的 IE9 调试模式是可以的, 看来模拟器还是模拟不到位.
查了好久, 终于看到一篇文章: Internet Explorer Aborting AJAX Requests : FIXED
主要的原因大概是 IE9 会将一个正在传输的请求 timeout 掉.
解决办法是:
onprogress
事件回调, 告知 IE9 这个请求是活动中的, 不要 timeout 掉.最终代码
结论
XDomainRequest
, 因为 IE9 下的XMLHttpRequest
不支持跨域调用.XDomainRequest
只支持 GET 和 POST method, 并且没有 response status code, 可以说是不完善的 HTTP 异步请求对象.whatwg-fetch1.0+
不支持 IE9, 是因为 [IE9 的状态码不符合 fetch 规范], 而 polyfill 的目标是 polyfill 规范, 而不是做兼容.References
XDomainRequest
XMLHttpRequest
XDomainRequest – Restrictions, Limitations and Workarounds
Internet Explorer Aborting AJAX Requests : FIXED
EOF