我有一个Web服务,其方法需要很长时间才能完成。 因此,我启动了ajax客户端。它发送请求并等待。 请求完成后,一切都很好。
但是,当我在浏览器中使用“重新加载/刷新”选项(例如Chrome)时,一切都会变得一团糟。 未决请求在新页面中显示为仍未决。提出了新的待处理请求,但是旧的请求仍然坐在那里。 新的请求延迟或停止响应。
服务器故障?并非如此,因为当我重新启动浏览器本身时,一切正常。
顺便说一句,在最新的Firefox上,当我在ajax提取期间重新加载页面时,我的ajax应用程序崩溃了。我的意思是它挂在第一个ajax请求上。当然,重新启动浏览器会有所帮助。
这里的配置:
我的服务是在本地主机上运行的WCF服务。服务响应GET
请求,但是必须使用与cookie一起发送的API密钥对它们进行身份验证。该服务主要返回JSON响应。
通信使用CORS,没有问题。
我使用MiniWeb服务器测试客户端。该应用程序是纯ECMAScript,没有框架或依赖项。
这是我的ajaxGet方法:
/**
* Performs a GET request to the WCF, returns response data.
* @param {any} path Request path without domain and service path.
* @returns {object} Response data.
*/
async ajaxGet(path) {
let isFirstCookieSet = false;
if (this.serviceDomain === undefined) this.parseBaseUrl();
Cookie.set({ "api-key": this.apiKey }, { "domain": this.serviceDomain, "path": this.servicePath });
let response = null;
try {
response = await fetch(this.baseUrl + path, {
"method": "get",
"mode": "cors",
"credentials": "include"
});
} catch (error) {
console.info("Caught error during fetch operation before getting response body.");
throw new BackendError(404, "Service not available");
}
if (response.status !== 200) throw new BackendError(response.status, response.statusText);
let container = await response.json();
let data;
for (let k in container) if (container.hasOwnProperty(k)) {
data = container[k];
break;
}
Cookie.set({ "base-url": this.baseUrl, "api-key": this.apiKey }, { "expires": DateTime.now.addYears(1).value, "samedomain": true });
return data;
}
好吧,这取决于我的其他代码(显然,该方法属于App
和DateTime
类的BackendError
类,但是在这里无关紧要。
如何防止这种奇怪的未定义行为?
是否有特殊的fetch
选项?我应该设置一个特定的请求标头吗?是否应该在Web服务中设置特定的响应标头?还有其他魔术吗?
更新: 我发现可以手动中止待处理的请求:
How do I cancel an HTTP fetch() request?
但是如果在重新加载浏览器时可以发送信号,它将起作用,并且AFAIK无法在发生脚本时执行任何脚本。还是有可能?
答案 0 :(得分:1)
长话短说:我们需要AbortController
和window.onbeforeunload
。
let abortController = new AbortController();
window.onbeforeunload = function(e) { abortController.abort(); };
let myResponse = await fetch(uri, { /* my other options */, "signal" : abortController.signal });
这里发生了什么?浏览器允许在请求刷新页面时执行某些清理操作(或选项卡关闭或关闭)。它位于window.beforeunload
事件处理程序中。然后,我的fetch()
调用得到可选的CancelationToken
对象,它是我的signal
实例中的AbortController
。触发控制器后,所有令牌都会收到中止信号并被取消。
MDN表示这件事是实验性的。无论如何,它可以在Firefox,Chrome和Opera上正常工作。