JavaScript - send AJAX call on tab close (DELETE request) - javascript

I want to send an AJAX DELETE request through Javascript when the user closes the tab. The flow is the following:
When the user attempts to close the tab, a onbeforeunload event takes place, then if the user confirms to leave the page the onunload event takes place and tries to execute the deleteRequest function, which is a synchronous ajax delete request.
window.onbeforeunload = function(){
return 'Are you sure you want to leave?';
};
window.onunload = function(){
deleteRequest();
};
function deleteRequest(){
let url = new URL("http://......");
let request = new XMLHttpRequest();
request.onreadystatechange = function () {
if(request.readyState == 4){
if(request.status === 200){
console.log('success');
}
}
}
request.open("DELETE", url, false);
try{
request.send();
}
catch(e){
console.log(e);
}
}
Unfortunately, it seems that Google Chrome does not support anymore this since when a tab closes it kills all the pending events, and in the console of the browser I can see the following message
DOMException: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'http://.....': Synchronous XHR in page dismissal. See https://www.chromestatus.com/feature/4664843055398912 for more details.
at deletRequest(.......js:411:17)
at window.onunload
Please note that I have already seen many topics on this issue before on SO but the solutions did not really help since most of them are out of date since the policy of chrome on this changed quite recently, like this or this.
It seems that most people propose navigator.sendBeacon to achieve this, but in the documentation I saw only ways to make a POST request using this, any thoughts? Thanks in advance.

You're pretty much SOL as far as using sendBeacon out of the box goes, as PUT and DELETE cannot be sent as you observed (only POST). For your XMLHttpRequest, Chrome is very explicit about saying, "hey, we used to send these synchronous XHR requests in beforeunload if you used a no-op loop, but we're not supporting that anymore":
Failed to execute 'send' on 'XMLHttpRequest' [...] Synchronous XHR in page dismissal.
Chrome is intentionally disallowing this behavior. You have no option except to modify the backend, i.e., set up an endpoint that will receive sendBeacon POST request like https://example.com/trigger-delete/ and trigger the DELETE call from the backend, or, if it's not your server, you'll actually have to set up a relay server you control to receive the POST (https://myrelay.com/forward-delete/)and then pass it along as a DELETE.
sendBeacon is the only way you're getting out of this, as far as I can tell.

Related

AJAX - Failed to load resource: net::ERR_EMPTY_RESPONSE

I'm running some javascript which uses a setInterval to trigger an AJAX request and then performs some actions based on the returned output. I'm quite confused with it, because it works perfectly on my home server, but now that I've put it out onto the web, I'm having problems.
The following error appears on Google Chrome:
http://www.domain.com/ajax/sound.php
Failed to load resource: net::ERR_EMPTY_RESPONSE
The error doesn't occur consistently however. Sometimes the scripts run for several minutes before an error occurs. Sometimes it all breaks down in seconds.
I've already checked the obvious solution - that my server-side script is returning nothing. I did this by commenting out the entire script and having it do nothing but return information. That didn't help.
I have several AJAX requests running from the same page, and all of them eventually return the same error (with their respective pages of code). I've tried isolating the requests and performing them one at a time at a slowed down rate, and have determined that the requests work in a general sense, but as soon as one of them sends an error, they all completely stop working and start sending the same error.
Once the errors occur, I get no response when I try to access any part of my site (even parts with no AJAX). Safari says "...the server unexpectedly dropped the connection. This sometimes occurs when the server is busy. Wait for a few minutes, and then try again." I've tried this in Explorer, Chrome, and Firefox as well with similar results. Thankfully, the site does come back up after a few minutes of making no AJAX requests.
An example of one of the AJAX requests is as follows:
//At the set interval, we create a string for the request:
function alef(){
string = "a='a'";
request(sound, "ajax/sound.php", string);
}
//That function fires off an AJAX request:
function request(fix, url, string){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
fix(xhttp.responseText);
}
}
xhttp.open("POST", url, true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(string);
}
//The AJAX request returns a result to be processed by the following function:
function sound(text){
if(text == "sound"){
insound.play();
}
}
Presume that my sound.php files says:
<?php echo "sound"; ?>
It doesn't say only that, but even when it did for testing purposes, I had the same problem.
Any solutions?

AJAX status 12030

I am sending an ajax XMLHttpRequest using the POST method. When the request is sent, I am getting a readyState of 4 with a status of 12030. I know 12030 is a Microsoft specific state code that indicate the connection was not sustained. However, I can't seem to find where my code would be causing this error. If I navigate to the page without using the ajax request, it loads fine. Below is the javascript method and the call line.
AJAX Method
/*Sends ajax request with post data that updates the content view via ajax on completion
* #param message : message after completion of ajax request
* #param url : url to request
* #param params : post parameters as string
*/
function changeAjaxPost(message, url, params) {
var ajx;
if (window.HXMLHttpRequest) {
UtilLogger.log(HtmlLogger.FINE, "Using XMLHttpRequest");
ajx = new XMLHttpRequest();
}
else {
UtilLogger.log(HtmlLogger.FINE, "Using ActiveXObject");
ajx = new ActiveXObject("Microsoft.XMLHTTP");
}
ajx.open("POST", url, true);
ajx.setRequestHeader("X-Requested-With", "XMLHttpRequest");
ajx.setRequestHeader("Content-Type", "text/html");
ajx.setRequestHeader("Content-length", params.length);
ajx.setRequestHeader("Connection", "close");
ajx.send(params);
ajx.onreadystatechange = function () {
document.write(ajx.readyState + ":" + ajx.status);
if (ajx.readyState == 4 && ajx.status == 200) {
alert(message);
updateContent();
}
else if (ajx.readyState == 4 && ajx.status == 400) {
alert("Page Error. Please refresh and try again.");
}
else if (ajx.readyState == 4 && ajx.status == 500) {
alert("Server Error. Please refresh and try again.");
}
}
}
Call Line
changeAjaxPost("Excerpt Saved", "./AJAX/myadditions_content.aspx", params);
http://danweber.blogspot.com/2007/04/ie6-and-error-code-12030.html
IE6 and error code 12030
If you are running Internet Explorer 6 and using Ajax, you may get some XMLHttpRequests terminated with code 12030.
Microsoft's knowledge base at http://support.microsoft.com/kb/193625 shows that this code is
12030 ERROR_INTERNET_CONNECTION_ABORTED
The connection with the server has been terminated.
Googling turned up no help; the people encountering this don't seem to be aware of how network sockets work, so I had to actually figure it out on my own.
This happens when the client thinks a connection has been kept open, and the server thniks it is closed. The server has sent a FIN, and the client has responded to that with an ACK. Running "netstat" on the Windows client shows that the connection is in the CLOSE_WAIT state, so IE6 really ought to have realized this before trying. This is entirely the client's fault. If you wait about 60 seconds, the Windows OS stack will retire the connection.
If you need to support IE6, you have some solutions, in various degrees of ugly:
retry the ajax request in case of error code 12030
if the browser is ie, send an empty request to the server ahead of each ajax request
bundle up your ajax requests such that the time between them is ( (greater than server_timeout) AND (less than server_timeout + one minute)
IE7, fwiw, will issue a RST over the CLOSE_WAIT socket as soon as it realizes it has an outgoing connection to make. That, and the socket will only stay in that CLOSE_WAIT state for about 5 seconds anyway.
Sometimes, using
setRequestHeader("Connection","close");
can cause problems in some browsers.
Removing this solves the problem.
Credit goes to #MikeRobinson

Coding with XMLHttpRequest for Safari Extension

In my extension, I create Access Level as "All" as well as I add whitelists as http://*/* too for every domain.
And I have following code in my JS file (which run as end script):
var feedbackmsg = "message goes here";
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', 'http://mysitename.com/feedback.php', true);
xmlhttp.onreadystatechange = handleServerResponse;
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xmlhttp.send("html=" + feedbackmsg);
function handleServerResponse() {
if (xmlhttp.readyState == 4) {
alert(xmlhttp.getAllResponseHeaders());
if (xmlhttp.status == 200) {
alert("send");
} else {
alert("error");
}
}
}
Whenever I run it, I am getting no header respond in alert box as well as error alert message. How can I resolve the problem?
Whether or not it's an extension, XMLHttpRequest (if injected into a page) isn't allowed to access anything outside the page's current domain, I think. The console just says that the request was cancelled. At least, that was the case for me when I tested it just now. (I didn't have any urls in the whitelist or blacklist when I tested, but the Access option was set to "all".)
You can try going to the same domain as the one you want to "call" with the XHR object in your code, and see if it succeeds then. If it does, you'll know it's because the domain of the page and the XHR request must match.
However, it appears you can do cross-site ajax request from the extension's global page (oddly enough). At least it seemed to work for me just now. That's actually a little scary (I'd prefer it to be more difficult to call up a random server from an extension) but it worked.
Don't know if that helps you out, though.

Intercept send mail AJAX request in Gmail

I'm trying to attach a callback to the "Send mail" ajax action in Gmail. I've been able to differentiate a Send mail action from other AJAX actions based on the request payload but have been unable to hook into the actual AJAX call.
Thus far, I've tried using overriding the XMLHttpRequest.open() method as detailed here. That hasn't worked. I've also tried overriding XMLHttpRequest.send(). Also failed.
Any thoughts? Much thanks in advance.
Google's trick is that they send the request from inside an iframe which has it's own JavaScript environment. However, since it is loaded from the same origin as the parent, you can still easily manipulate it even from the browser console:
[].slice.apply(document.querySelectorAll('iframe')).forEach(function (iframe) {
try {
var xhrProto = iframe.contentWindow.XMLHttpRequest.prototype;
var origOpen = xhrProto.open;
xhrProto.open = function () {
console.log('DO SOMETHING', arguments);
return origOpen.apply(this, arguments);
};
} catch (e) {}
});
You might want to use a MutationObserver to detect newly added iframes reliably.

Why does this XMLHttpRequest POST fail to even connect to the server?

I have an XMLHttpRequest opened with the POST method, to a URL that I know exists because I've just done a GET on it.
However, the send() call on the XHR doesn't actually open any connection to the server or send any data -- I've verified this with WireShark.
Instead, it just fails the request, calls the onreadystatechange event handler, setting status to 0 (meaning, according to the spec, that the "error flag" is set).
But... there's no way for me to inspect WHAT is going wrong. I've tried this in FireBug, and the headers and body look OK; there is no response body or response headers. The line in the console output is a POST /url (x) where the (x) is a red circle with an X in it. No error reason is visible anywhere. That same line is not in the NET panel at all. This is probably a clue, but I don't know of what.
function save_edits(url, txt, cb)
{
var xhr = new XMLHttpRequest();
console.log("'POST' " + url);
xhr.open('POST', url, true);
xhr.onreadystatechange = function(ev)
{
if (xhr.readyState == 4)
{
console.log('post complete status:' + xhr.status);
cb();
}
}
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var text = "&" + edit_what + "=" + escape(txt.replace(/\r/g, '\n'));
try
{
xhr.send(text);
}
catch (e)
{
console.log('send() error: ' + e.toString());
}
This outputs in the FireBug console:
'POST' http://mydomain.com/srv.json.section-xna.latest
POST http://mydomain.com/srv.json.section-xna.latest source.js (line 70)
post complete status:0
Line 1) is my console log statement.
Line 2) is the POST XHR request, which is red, with the circle-X showing failure.
Line 3) is the console log statement from the onreadystatechange handler.
There is no exception raised (I put that check in there just for paranoia) -- even if I make the open() be synchronous instead of asynchronous.
Again, this is not a server-side problem, because the request doesn't even make it onto the wire, and I don't know how to figure out why that is.
Is the URL on your domain or an alternative domain? If it is an alternative domain you are most likely being blocked due to cross domain security issues.
Thanks for the suggestions, everyone! It turns out to be a problem at a higher level.
The code that was calling the save function was then immediately calling window.location.reload() to see the new data, which ended up canceling the outstanding POST request.
Can't believe I had to go through WireShark AND Stack Overflow just to be able to see that problem...

Categories