最近在测试环境遇到一个请求失败的问题:
控制台在抛出如图的错误之后便对发起的请求抛出了异常,导致后面的代码执行不下去。
从网上查找该报错Failed to set the 'responseType' property on 'XMLHttpRequest'
,发现是由于在同步请求中尝试修改XMLHttpRequest
的 responseType
属性时便会抛出该异常
但是发起的请求时异步请求啊,为什么会抛出该异常呢?
经过排查,发现日常环境对 XMLHttpRequest 对象做了重写,用于在测试环境的资源链接进行替换。
XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
console.log(`method:${method}\turl:${url}\tasync:${async}\tuser:${user}\tpass:${pass}`)
XMLHttpRequest.prototype.open.call(this, method, url, async, user, pass);
};
这个重写乍一看好像没有什么问题,但是它对于 async
参数的处理导致了错误的发生:
对于 XMLHttpRequest
对象的 open
方法的 async
参数,如果不传的话,则会默认为 true
,而经过测试环境对 open
方法的重写,导致所有的请求在执行 open
方法时,当没有传 async
时,这里就会将 async
参数置为undefined
,再继续向下传递时,对于 undefined
的 async
属性会被认为是 false,而不是默认的 true
,此时请求作为 sync
同步请求发起。而同步请求是禁止修改 responseType
属性的,因此当在设置 responseType
属性的时候,便抛出了上面的错误。
用下面的代码进行测试,会抛出异常:
/**
* 使用 XMLHttpRequest 实现原生 fetch 发起请求,
*/
// 保存原有的 open 方法
const rawOpen = XMLHttpRequest.prototype.open;
// 重写原有的 open 方法,在打印相关参数后再调用原生方法
XMLHttpRequest.prototype.open = function (method, url, xasync, user, pass) {
console.log(`method:${method}\turl:${url}\tasync:${xasync}\tuser:${user}\tpass:${pass}`)
rawOpen.call(this, method, url, xasync, user, pass);
};
var xhr = new XMLHttpRequest(); //实例化XMLHttpRequest 对象
// 调用 open 方法,发起请求
xhr.open("GET","https://catfact.ninja/fact")
// 设置响应类型为 arraybuffer
xhr.setResponseType = "arraybuffer";
// 当状态发生变化的时候执行对应方法
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
console.log(xhr.responseText); //接收数据
}
}
}
// 发送空结果
xhr.send(null);
// 还原原有的 open 方法
XMLHttpRequest.prototype.open = rawOpen;
而修改起来也很简单,对于 undefined
的async
参数,重新给一个 默认值 true
即可。
// 第四行,调整async默认值为 true
rawOpen.call(this, method, url, async == undefined ? true : async, user, pass);
希望我的排错经历能够帮助到你。
参考资料
Failed to set the ‘responseType’ property on ‘XMLHttpRequest’
XMLHttpRequest.open()
XMLHttpRequest.responseType
Not able to use HttpClient in angular 5