I have been struggling to write code that will make a POST request reliably on close of the tab window. Navigator.sendBeacon
seems to be exactly what I need (I only require this to work for Google Chrome).
$(global).bind('unload', function () {
let body = {
UserEmail: appState.user.email,
Job: {
Id: appState.jobId
},
Timestamp: '/Date(' + new Date().getTime() + ')/',
EventOrigin: 'PdfReviewClient',
Event: 'JobClosed'
};
let headers = {
Authorization: `JWT ${authenticationState.token}`,
'Content-Type': 'application/json; charset=utf8'
};
let blob = new Blob([JSON.stringify(body)], headers);
navigator.sendBeacon(configuration.rootApiUrl + 'jobevents', blob);
});
My beacon includes custom headers, that's why I create a Blob.
However, this request does not seem to be happening. This is especially hard to debug since the window closes. So the question is, why is my beacon not sending?
The issue was the only header you can set with navigator.sendBeacon
is Content-Type, and you set that by setting type
in the Blob options. The server route had to be modified to accommodate the request without an Authorization header (I passed it as a URL parameter instead - weird for a POST request, but seemingly the only way to do that with a beacon). Here's how it looked in the end:
$(global).bind('unload', function () {
if(appState.jobId == null) return;
let headers = {
type: 'application/json'
};
let jobEventLoggingBody = {
UserEmail: appState.user.email,
Job: {
Id: appState.jobId
},
Timestamp: '/Date(' + new Date().getTime() + ')/',
EventOrigin: 'PdfReviewClient',
Event: 'JobClosed'
};
let jobEventLoggingUrl = `${configuration.rootApiUrl}jobevents?jwt=${authenticationState.token}`;
let jobEventLoggingBlob = new Blob([JSON.stringify(jobEventLoggingBody)], headers);
navigator.sendBeacon(jobEventLoggingUrl, jobEventLoggingBlob);
});
See also this question which specifically addresses sending headers in beacons.