我有一个 Web 服务,其方法需要相当长的时间才能完成。 所以我启动了ajax客户端。它发送请求并等待。 请求完成后一切都很好。
但是当我在浏览器(比如说 Chrome)中使用重新加载/刷新选项时,一切都崩溃了。 待处理的请求在新页面中显示为仍待处理。新的待处理请求已发出,但旧的请求仍保留在那里。 新请求滞后或停止响应。
服务器故障?不是真的,因为当我重新启动浏览器本身时一切正常。
顺便说一句,在最新的 Firefox 上,当我在 ajax 获取期间重新加载页面时,我的 ajax 应用程序崩溃了。我的意思是它卡在第一个ajax请求上。当然,重新启动浏览器会有所帮助。
配置如下:
我的服务是在本地主机上运行的 WCF 服务。该服务响应 GET
请求,但必须使用通过 cookie 发送的 API key 对它们进行身份验证。该服务主要返回 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
选项?我应该设置特定的请求 header 吗?我应该在我的 Web 服务中设置特定的响应 header 吗?还有其他魔法吗?
更新: 我发现我可以手动中止待处理的请求:
How do I cancel an HTTP fetch() request?
但是,如果我可以在浏览器重新加载时发送信号,那么它就会起作用,并且据我所知,当它发生时,无法执行任何脚本。或者说有可能吗?
最佳答案
长话短说:我们需要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 对象,它是来 self 的 AbortController 实例的信号。当 Controller 被触发时,所有 token 都会收到中止信号并被取消。
MDN 说这个东西是实验性的。不管怎样,它在 Firefox、Chrome 和 Opera 上都能正常工作。
关于javascript - 挂起的 ajax 获取期间页面重新加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51471901/