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...
Related
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.
I have a problem with a webservice i need to call to.
Situation
I need to get information from a webservice, build by the company I work for. If i try to get the information via SOAPUI there isn't any problem and i get the information i need in the response. But after editing a script so i can get it via the browser i get a 500 error.
Code
function soap() {
try {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', 'https://**testserver**/test/services/smsproxy2.smsproxy2HttpsSoap11Endpoint', true);
// build SOAP request
var sr =
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sms="http://**service**/smsreport">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<sms:GetSMSReport>' +
'<sms:FromDate>2015-01-01</sms:FromDate>' +
'<sms:ToDate>2015-12-12</sms:ToDate>' +
'</sms:GetSMSReport>' +
'</soapenv:Body>' +
'</soapenv:Envelope>';
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
alert('Working fine! See the console.');
}
}
}
// Send the POST request
xmlhttp.setRequestHeader('Content-Type', 'text/xml');
var result = xmlhttp.send(sr);
}
catch (error) {
alert('An error occurred: ' + error);
}
}
soap();
Explanation
This entire code is put in a html file. This code is between script tags in the html head tag.
The **testserver** and **service** parts are different in the real script.
Problem
As soon as i open this (html)file in the browser, i get an 500 (internal Error) message in the console. The row which is specified with this message is the row on which the xmlhttp.send(sr) action is set.
Effect
I can't get the information i need within the server. So i can't show anything on the webpage.
Questions
Why do i get a 500 error in the browser and does this work without problems in SOAP UI? The URL which is called is exactly the same in the browser as it is in SOAP UI, so this shouldn't be possible.
How do i solve this?
Tried
A lot of things, but nothing helped.
After making the connection easier (directly and not via a proxy), there was an error in the errorlog.
It said that the endpoint wasn't right, but this seemed okay. Also the XML seemed okay.
After trying some things i found the solution:
Solution
The following row gives the error:
xmlhttp.setRequestHeader('Content-Type', 'text/xml');
I've deleted this row from my script and now it works fine.
I found this bizarre, but I recently change all my paths from relative to absolute.
I see that ajax appears to be working fine in the console as I can see the files retrieved successfully, with a status of 200.
Here is a pic: (its small but hopefully you can make out the status 200)
However, my callback functions stopped running, here is the code:
if (config_ajax.type === 'get') {
xhr = new win.XMLHttpRequest();
xhr.open('GET', config_ajax.url, true);
xhr.onload = function () {
if (this.status === 200) {
$A.log('succeeded with status 200'); // never gets here
config_ajax.callback(xhr.responseText);
}
};
xhr.send(null);
}
you have an incorrectly formatted request to the server as shown in firebug
http://www.arcmarks.com/http://www.arcmarks.com/arcmarks/source/class.CMachine.php
note the http://www shows twice
If the page is at arcmarks.com, it cannot make AJAX requests to www.arcmarks.com - browsers enforce something called the Same Origin Policy which prevents you from sending AJAX requests to any domain other than the exact one the original page was served from.
Also, the comment about the request being sent to www.www.arcmarks.com is right - as the code adds a "www" to the current URL, if your URL has a www in it already it will be repeated. But I'm assuming this was intentional.
I'm using javascript to pass a dynamic url to iframe src. but sometimes the url does not exist, how could i detect the non-exist url beforehand, so that i can hide the iframe that with 404 error.
Due to my low reputation I couldn't comment on Derek 朕會功夫's answer.
I've tried that code as it is and it didn't work well. There are three issues on Derek 朕會功夫's code.
The first is that the time to async send the request and change its property 'status' is slower than to execute the next expression - if(request.status === "404"). So the request.status will eventually, due to internet band, remain on status 0 (zero), and it won't achieve the code right below if. To fix that is easy: change 'true' to 'false' on method open of the ajax request. This will cause a brief (or not so) block on your code (due to synchronous call), but will change the status of the request before reaching the test on if.
The second is that the status is an integer. Using '===' javascript comparison operator you're trying to compare if the left side object is identical to one on the right side. To make this work there are two ways:
Remove the quotes that surrounds 404, making it an integer;
Use the javascript's operator '==' so you will be testing if the two objects are similar.
The third is that the object XMLHttpRequest only works on newer browsers (Firefox, Chrome and IE7+). If you want that snippet to work on all browsers you have to do in the way W3Schools suggests: w3schools ajax
The code that really worked for me was:
var request;
if(window.XMLHttpRequest)
request = new XMLHttpRequest();
else
request = new ActiveXObject("Microsoft.XMLHTTP");
request.open('GET', 'http://www.mozilla.org', false);
request.send(); // there will be a 'pause' here until the response to come.
// the object request will be actually modified
if (request.status === 404) {
alert("The page you are trying to reach is not available.");
}
Use a XHR and see if it responds you a 404 or not.
var request = new XMLHttpRequest();
request.open('GET', 'http://www.mozilla.org', true);
request.onreadystatechange = function(){
if (request.readyState === 4){
if (request.status === 404) {
alert("Oh no, it does not exist!");
}
}
};
request.send();
But notice that it will only work on the same origin. For another host, you will have to use a server-side language to do that, which you will have to figure it out by yourself.
I found this worked in my scenario.
The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callback methods introduced in jQuery 1.5 are deprecated as of jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.
$.get("urlToCheck.com").done(function () {
alert("success");
}).fail(function () {
alert("failed.");
});
I created this method, it is ideal because it aborts the connection without downloading it in its entirety, ideal for checking if videos or large images exist, decreasing the response time and the need to download the entire file
// if-url-exist.js v1
function ifUrlExist(url, callback) {
let request = new XMLHttpRequest;
request.open('GET', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('Accept', '*/*');
request.onprogress = function(event) {
let status = event.target.status;
let statusFirstNumber = (status).toString()[0];
switch (statusFirstNumber) {
case '2':
request.abort();
return callback(true);
default:
request.abort();
return callback(false);
};
};
request.send('');
};
Example of use:
ifUrlExist(url, function(exists) {
console.log(exists);
});
You could test the url via AJAX and read the status code - that is if the URL is in the same domain.
If it's a remote domain, you could have a server script on your own domain check out a remote URL.
Using async/await, this worked for me for opening a new tab; I needed to detect a 404 for the same reason as the OP:
openHelp : async function(iPossiblyBogusURL) {
const defaultURL = `http://guaranteedToWork.xyz`;
const response = await fetch(iPossiblyBogusURL);
if (response.status == 200) {
window.open(iPossiblyBogusURL, `_blank`);
} else if (response.status === 404) {
window.open(defaultURL, `_blank`);
}
},
You can try and do a simple GET on the page, if you get a 200 back it means the page exists. Try this (using jQuery), the function is the success callback function on a successful page load. Note this will only work on sites within your domain to prevent XSS. Other domains will have to be handled server side
$.get(
yourURL,
function(data, textStatus, jqXHR) {
//load the iframe here...
}
);
There is no need to make a separate HTTP request to check beforehand.
You could switch the logic around: only display the iframe if it has been loaded successfully. For this purpose, you can attach an onload event listener to the iframe.
See this related question for details: Capture iframe load complete event
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.