我正在将大量事件以 20 个事件为一组发送到 BigQuery 中的分析表。最初,我使用
sendBeacon
,但后来改用常规 POST
请求。下面是我用来处理发送事件的类:
import { createControllablePromise, delay } from '../utils/generalUtils';
class EventReporterWorker {
#requestQueue = Promise.resolve();
#activeRequest;
#isPageVisible = true;
#handleSendEvents = async eventsPayload => {
if (this.#isPageVisible) {
await this.#activeRequest;
}
const currentRequestPromise = createControllablePromise();
const cancelTimeout = setTimeout(() => currentRequestPromise.resolve(), 30000);
currentRequestPromise.finally(() => clearTimeout(cancelTimeout));
this.#activeRequest = currentRequestPromise;
const requestPromise = fetch('*MY_URL*, {
method: 'POST',
headers: {
accept: '*/*',
'cache-control': 'no-cache',
'content-type': 'text/plain;charset=UTF-8',
},
body: eventsPayload,
keepalive: true,
mode: 'no-cors', // Matches sendBeacon's behavior
});
requestPromise.finally(() => {
currentRequestPromise.resolve();
});
if (this.#isPageVisible) {
try {
await delay(300);
await requestPromise;
} catch (e) { }
}
};
sendEvents = async eventsPayload => {
const newRequestsQueue = this.#requestQueue.then(() => this.#handleSendEvents(eventsPayload));
this.#requestQueue = newRequestsQueue;
return newRequestsQueue;
};
setPageVisible = isPageVisible => {
this.#isPageVisible = isPageVisible;
if (!isPageVisible) {
this.#activeRequest.resolve();
}
};
}
export const eventReporterWorker = new EventReporterWorker();
我使用 Promise 是因为我从多个地方接收事件并希望它们按顺序执行。我唯一希望立即发送所有事件的是当我切换选项卡时。
但是,切换选项卡时,某些
POST
调用失败并停留在 Pending
状态。
错误信息是:
Uncaught (in promise) TypeError: Failed to fetch
此失败之前和之后的事件成功,如图所示。
有人遇到过这个问题或者有解决办法吗?
我尝试过批量发送事件,增加延迟,检查服务器(问题不在服务器端),并确认互联网连接正常。调用似乎在浏览器级别失败。
似乎你也有类似的案例这里。 “
TypeError: Failed to fetch
”错误通常有多种原因发生:
错误或不完整的 URL 已传递给 fetch() 方法。
您发出请求的服务器未发回正确的 CORS 标头。
网址中指定了错误的协议。
错误的方法或标头已传递给 fetch() 方法。
虽然 keepalive 旨在帮助解决此问题,但它并不能保证请求会完成。您的模式:“no-cors”会加剧问题,因为 no-cors 请求可返回的信息有限,因此很难检测实际失败与浏览器终止的请求。
除非绝对必要,否则请避免 no-cors。它严重限制了错误处理,并且可能隐藏有关请求失败的重要信息。建议在服务器上正确配置 CORS。