待处理的ajax提取期间页面重新加载

时间:2018-07-23 05:12:24

标签: javascript ajax wcf

我有一个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;
}

好吧,这取决于我的其他代码(显然,该方法属于AppDateTime类的BackendError类,但是在这里无关紧要。

如何防止这种奇怪的未定义行为? 是否有特殊的fetch选项?我应该设置一个特定的请求标头吗?是否应该在Web服务中设置特定的响应标头?还有其他魔术吗?

更新: 我发现可以手动中止待处理的请求:

How do I cancel an HTTP fetch() request?

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

1 个答案:

答案 0 :(得分:1)

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

MDN表示这件事是实验性的。无论如何,它可以在Firefox,Chrome和Opera上正常工作。