This code calls a backend method during the "beforeunload" event via the Fetch API.
What this does and why:
I work as a corporate Backend Programmer, and I need to remove something from the session (which isn't available at the frontend...) when the tab with the page is closed, the browser is closed, the page is refreshed or the URL is redirected somewhere else (for example when clicking a link). Our last senior Frontend Programmer left the company months ago. Woe is me.
sendBeacon cannot be used due to its limits and the web application security. Synchronous ajax requests no longer work in the "beforeunload" event for Chromium-based browsers. Which left me with using Fetch API with keepalive.
I did leave the Czech comments for posterity. PS: Google translate doesn't work all that well for Czech.
Code: Select all
window.addEventListener("beforeunload", function(event) {
*here should be code that gets attributeName and attributeValueToRemove, but believe it or not, the rest of the code has been extracted from a multitude of functions and these two params are just Strings, so feel free to use whatever instead*
var data = new FormData();
var token = $("meta[name='_csrf']").attr("content");
//------------- POZOR - následující věci jsou extrémně háklivé na cokoliv!! Funguje to divně!----------------
// add your data
//Nefunguje, píše to Required String parameter 'attributeName' is not present.
/* data.append("attributeName", attributeName);
data.append("attributeValueToRemove", attributeValueToRemove);*/
// add the auth token - u nás dle formulářů
data.append("_csrf", token);
//sendBeacon je extrémně omezený a nefunguje s naším zabezpečením aplikace, takže nelze použít, přestože tohle
// je přesně jeho účelem
//navigator.sendBeacon(url("/session/removeFromSessionArrayDuringUnload"), data);
//Protože ajaxové volání je v synchronní podobě při unload eventech zakázáno a asynchronně nedojde do konce,
// a sendBeacony nefungují s naším zabezpečením aplikace, tak použijeme Fetch API.
//https://github.com/w3c/beacon/pull/27#issuecomment-241549321
//https://stackoverflow.com/questions/38027231/how-to-make-navigator-sendbeacon-use-get-method
//https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
//https://stackoverflow.com/questions/40893537/fetch-set-cookies-and-csrf
const headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Connection': 'keep-alive',
'X-CSRF-TOKEN': token
});
//PS: potencionální TODO Chrome se může kdykoliv rozhodnout Fetch API při on before unload eventu omezit nebo
// zakázat, tak jak to udělal se synchronním ajaxem při této události. Správně se tady
// má použít sendBeacon, jenže ten je tak naschvál omezený, že se při našem zabezpečení
// (csrf token, atd.) není možné spojit s backendem, nebo aspoň mě se to celé hodiny
// nedařilo. Tzn. je možné, že dobudoucna bude nutné tohle předělat, když se něco
// takového autoři Chromu rozhodnou provést a zakázat.
//Proč jsou parametry v url viz komentář u data.append("attributeName"
fetch(url("/session/removeFromSessionArrayDuringUnload?attributeName=" + attributeName + "&attributeValueToRemove=" + attributeValueToRemove), {
method: "POST",
cache: 'no-cache',
body: data /*{
//Nefunguje, píše to Required String parameter 'attributeName' is not present.
"attributeName": attributeName,
"attributeValueToRemove": attributeValueToRemove,
"_csrf": token
}*/,
headers: headers,
credentials: 'include',
mode: 'cors',
keepalive: true,// i.e. don't terminate when fetch group is terminated - díky tomuhle se dotaz dodělá
// až do konce, ikdyž se třeba zavírá prohlížeč
}).then(r => console.log("removeFromSessionArrayDuringUnload has finished!"));
//Hack pro firefox - https://stackoverflow.com/questions/67754620/fetch-keep-alive-is-not-working-as-expected
const time = Date.now();
while ((Date.now() - time) < 500) {}
//Viz dlouhé TODO někde výše, proč není použit beacon.
//navigator.sendBeacon(url("/session/removeFromSession?attributeName=" + attributeName + "&attributeValueToRemove=" + attributeValueToRemove));
});