在挂起的 ajax 提取期间重新加载页面



我有一个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 服务中设置特定的响应标头吗?还有其他魔法吗?

更新:我发现我可以手动中止挂起的请求:

如何取消 HTTP fetch() 请求?

但是,如果我可以在浏览器重新加载时发送信号,并且 AFAIK 在发生时无法执行任何脚本,它将起作用。还是可能?

长话短说:我们需要AbortControllerwindow.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对象是可选的,它是我的AbortController实例中的signal。当控制器被触发时,所有令牌都会收到中止信号并被取消。

MDN说这个东西是实验性的。无论如何,它可以与Firefox,Chrome和Opera一起使用。

最新更新