I'm attempting to retrieve a url using XMLHttpRequest directly:
req = new XMLHttpRequest
req.onreadystatechange = ->
console.log req.readyState
if req.readyState == 1
console.log "sending..."
req.send
if req.readyState == 4
handler(req.response, req.status)
req.open("GET", info.srcUrl, true)
req.responseType = "arraybuffer"
But I never see the object transitioning beyond the 1 readyState. What am I missing?
If you are attempting to retrieve an arbitrary resource from another source than the server from which you received the running script, you are more than likely hitting a security issue related to Cross Site Scripting.
Except under very limited circumstances, you cannot retrieve resources from any other site but the one that served the page you are currently viewing.
For an explanation, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript?redirectlocale=en-US&redirectslug=JavaScript%2FSame_origin_policy_for_JavaScript
For the limited circumstances I mentioned above, see https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control
Further, since you do not appear to provide an error handler for your XMLHTTPRequest, you're more than likely missing the error message which would have informed you why your request had failed.
Update
A quick tutorial on XMLHTTPRequest, including how to handle an onError event can be found at https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest
Coming from Ruby, I did not realize that there is a subtle but important difference between req.send and req.send(). As #RobW pointed out in the comments, this method should also not be called in the event handler but at the end of the code.
Related
I have a content script in my Chrome extension which runs on some HTTPS page. It is trying to send a POST request to an HTTP page (by means of a background script) which is a route for an API that I have set up. I am trying to send JSON data over. However I am getting status 0, even though the ready state is 4. I used Postman to perform the same post and it worked. This leads me to believe it is a HTTPS protocol issue, however I am performing a GET on an HTTP page in the same background script and that is working fine. What might be the issue then? Here is my POST code:
var string = json;
xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var json = JSON.parse(xhr.responseText);
}
};
xhr.send(string);
Thanks!
UPDATE:
I used the chrome developer tools to debug the background script and I found the error, which was "Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.". I guess background script errors do not print to the main console.
UPDATE:
I had to add the site I was posting to to the permissions field in my manifest. It works now.
I have a similar issue and, after debugging it for days, the only solution I found was to make the XMLHttpRequest synchronous by setting set the async param in the XMLHttpRequest open method to false.
The readyState value of 4 means the operation completed successfully or failed. The status property is initialized to 0 and will remain at 0 if an error occurs. Assign an event handler to the xhr.onerror property and I bet you'll see that handler fire. Unfortunately, the error event doesn't give any useful information about what caused the error.
To find out what caused the error, I would use the debug tools found in Chrome. Menu => More tools => Developer Tools. Then go to the "Network" tab. There you can see all the HTTP requests your webpage has made. It will show better details on any errors there.
What did you do?
I had to add the site I was posting to the permissions field in my manifest. It works now.
XMLHttpRequest.setRequestHeader("Access-Control-Allow-Origin", "the api website"); ?
I have run in to a problem. Please help with your expertise.
I am developing web solution for a company. They have provided me Web API Method (REST). This API is in their domain. I am too access this from my domain. Even client has also already whitelisted my domain.
I am trying to call this method using below. But no luck. I am getting this below error.
Error NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
function GetCustomerInfo()
{
var Url = "http://webapi.company.com/vx.x/customer/get?format=xml&mobile=9876543210" ;
myXmlHttp = new XMLHttpRequest();
myXmlHttp.withCredentials = true;
myXmlHttp.onreadystatechange = ProcessRequest;
myXmlHttp.open( "GET", Url, true,"UID","PWD");
myXmlHttp.send();
}
function ProcessRequest()
{
if(this.readyState == this.DONE)
{
if(this.status == 200 && this.responseXML != null )
{
alert ("Received Resoponse from Server");
}
else
{
alert ("Some Problem");
}
}
}
I am able to access this method from RESTClient in firefox plugin.
Even I am able to access this method copying credentials in URL as below in browser address bar. I get anticipated response XML
http://UID:PWD#webapi.company.com/vx.x/customer/get?format=xml&mobile=9876543210
Please enlighten me where I am wrong. Perhaps JSONP can come to my help. But why i am not able to access this API using XMLHttpRequest.
Regards
Rajul
The same origin policy of the browser does not allow you to send XMLHttpRequests to a different domain. The reason you can access it through a firefox plugin or the address bar is that the same origin policy is not applied there.
You are right, JSONP could solve your problem, although you may run into trouble because you do not control the serverside.
In response to your comment: In order to use JSONP effectively, the server will need to return not only the data you need in JSON format, but also javascript code to invoke a callback when the request is done. If you do not control the data that is returned, you can not add the necessary code for this. The wikipedia article gives a good example for the general case.
I have never used CORS, thus can not give you much information on it. It seems like a better solution, but I imagine it is not incredibly compatible across browsers. Also, as I understand it, you will need control of the server as well, as it seems to require additional HTTP headers.
I have a site that I enter a username/password and click a login button. The login button makes an XMLHttpRequest object, and fires it off.
On Chrome, Firefox, Opera, Safari, Android devices, iOS devices this works fine.
IE9 will work fin so long as I am on an HTTP address and not using HTTPS.
On HTTPS, IE9 behaves as follows:
The first login request never returns anything back. The F12 screen does show my login request in the network tab and all looks correct. The scripting tab never throws an error. Simply nothing happens.
Here's the crazy part:
- If I click login a second time, it actually works.
- If I click refresh on the browser, and then login, that will work as well!
I am making the request as follows:
var x = new XMLHttpRequest();
x.open("POST", "/Relative/URL/Path", true);
x.setRequestHeader("Content-Type", "text/plain");
x.onreadystatechange = function () {
if ((x.readyState == 4) && (x.status == 200)) {
// handle callback
}
}
x.send(my request);
When this fails, the debugger will go from the x.send() line into the onreadystatechange code. The readyState will be 1. This will be the last I can debug because nothing else happens.
Any ideas would be extremely appreciated.
[EDIT]: I let one request go to see what would happen. The onreadystatechange event fired again with readyState = 4 and status = 12152. The network view in IE9's F12 screen shows the result as Aborted and the time taken as 1589.07s. A Google search shows this means the connection was closed on the server.
[EDIT 2]: Based on a comment below I redid this code to just use jQuery's ajax() method. I thought this might have a chance at eliminating bad code on my part. No such luck. The same behavior occurs.
$.ajax({
"url": sUrl,
"success": function (data, textStatus, x) {
workerCallback(data, id, "");
},
"error": function (x, testStatus, errorThrown) {
workerCallback("nc", id, errorThrown);
},
"contentType": "text/plain",
"data": JSON.stringify(req),
"dataType": "json",
"timeout": 1600000,
"type": "POST"
});
[FINAL UPDATE:] I've updated the code. If a timeout occurs, I simply repost the same request - one time only. Quite the hack but it works. Unless anyone finds the solution I'll split the bounty between a few helpful ideas people have had below.
This seems like a strange issue and it's hard to test it without poking around the code on an https site.
If you want a quick fix you could try doing an initial (dummy) request then abort it right away with a short setTimeout and make a second (real) request.
As per your description it should work.
during debug on the first request this came through
There is a related post to this exact error...
IE 9 Javascript error c00c023f
The author put the following in the onreadystatechange handler
if (xmlHttpRequest.aborted==true) {
stopLoadAnimation();
return;
}
This may help point you in the right direction.
Timeouts prevents the request from being terminated at readyState 1, and it succeeds afterwards due to content sniffing.
Configure SSL client authentication on the login form using the web server config
Insert a hidden element (such as an image) that references an URL that requires SSL client authentication
Use a protocol relative gif hyperlink, such as //example.com/image.gif, to avoid the SEC7111 mixed content vulnerability
The URL of the open method matches the domain when using HTTP, but not HTTPS, which causes the request to fail, but subsequent requests fallback to the security zone policy
Use a comparison between window.location.protocol and document.location.protocol to check whether the script is executing in the same context as the page
Sending JSON as MIME type text/plain may trigger content sniffing
Compare the Accept header between the requests that fail versus those that succeed
HTTPS Caching may be an issue
The Connection header may need to be set
Proxy configuration may be an issue
The initial header response values may be too large (e.g. HTTP status description has a limit of 512 characters)
document.readystate may not be complete on the initial request, which causes premature execution problems
Certificate revocation checks may block the initial JSON POST, but allow subsequent requests after the GET callback
readyState and status properties should be referenced using the callback scope rather than the variable x to avoid using the closure scope:
function cb()
{
if ( (this.readyState === 4) && (this.status === 200) )
{
// handle callback
}
}
onreadystatechange = cb;
I know very, very little of javascript, but I'm interested in writing a script which needs information from another webpage. It there a javascript equivalent of something like urllib2? It doesn't need to be very robust, just enough to process a simple GET request, no need to store cookies or anything and store the results.
There is the XMLHttpRequest, but that would be limited to the same domain of your web site, because of the Same Origin Policy.
However, you may be interested in checking out the following Stack Overflow post for a few solutions around the Same Origin Policy:
Ways to circumvent the same-origin policy
UPDATE:
Here's a very basic (non cross-browser) example:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/questions/3315235', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(xhr.responseText);
}
};
xhr.send(null);
If you run the above in Firebug, with Stack Overflow open, you'd get the HTML of this question printed in your JavaScript console:
JavaScript access another webpage http://img217.imageshack.us/img217/5545/fbugxml.png
You could issue an AJAX request and process it.
Write your own server, which runs the script to load the data from websites. Then from your web page, ask your server to fetch the data from websites and send them back to you.
see http://www.storminthecastle.com/2013/08/25/use-node-js-to-extract-data-from-the-web-for-fun-and-profit/
I have written an XMLHttpRequest which runs fine but returns an empty responseText.
The javascript is as follows:
var anUrl = "http://api.xxx.com/rates/csv/rates.txt";
var myRequest = new XMLHttpRequest();
callAjax(anUrl);
function callAjax(url) {
myRequest.open("GET", url, true);
myRequest.onreadystatechange = responseAjax;
myRequest.setRequestHeader("Cache-Control", "no-cache");
myRequest.send(null);
}
function responseAjax() {
if(myRequest.readyState == 4) {
if(myRequest.status == 200) {
result = myRequest.responseText;
alert(result);
alert("we made it");
} else {
alert( " An error has occurred: " + myRequest.statusText);
}
}
}
The code runs fine. I can walk through and I get the readyState == 4 and a status == 200 but the responseText is always blank.
I am getting a log error (in Safari debug) of Error dispatching: getProperties which I cannot seem to find reference to.
I have run the code in Safari and Firefox both locally and on a remote server.
The URL when put into a browser will return the string and give a status code of 200.
I wrote similar code to the same URL in a Mac Widget which runs fine, but the same code in a browser never returns a result.
Is http://api.xxx.com/ part of your domain? If not, you are being blocked by the same origin policy.
You may want to check out the following Stack Overflow post for a few possible workarounds:
Ways to circumvent the same-origin policy
PROBLEM RESOLVED
In my case the problem was that I do the ajax call (with $.ajax, $.get or $.getJSON methods from jQuery) with full path in the url param:
url: "http://mydomain.com/site/cgi-bin/serverApp.php"
But the correct way is to pass the value of url as:
url: "site/cgi-bin/serverApp.php"
Some browser don't conflict and make no distiction between one text or another, but in Firefox 3.6 for Mac OS take this full path as "cross site scripting"... another thing, in the same browser there is a distinction between:
http://mydomain.com/site/index.html
And put
http://www.mydomain.com/site/index.html
In fact it is the correct point view, but most implementations make no distinction, so the solution was to remove all the text that specify the full path to the script in the methods that do the ajax request AND.... remove any BASE tag in the index.html file
base href="http://mydomain.com/" <--- bad idea, remove it!
If you don't remove it, this version of browser for this system may take your ajax request like if it is a cross site request!
I have the same problem but only on the Mac OS machine. The problem is that Firefox treat the ajax response as an "cross site" call, in any other machine/browser it works fine. I didn't found any help about this (I think that is a firefox implementation issue), but I'm going to prove the next code at the server side:
header('Content-type: application/json');
to ensure that browser get the data as "json data" ...
The browser is preventing you from cross-site scripting.
If the url is outside of your domain, then you need to do this on the server side or move it into your domain.
This might not be the best way to do it. But it somehow worked for me, so i'm going to run with it.
In my php function that returns the data, one line before the return line, I add an echo statement, echoing the data I want to send.
Now sure why it worked, but it did.
Had a similar problem to yours. What we had to do is use the document.domain solution found here:
Ways to circumvent the same-origin policy
We also needed to change thins on the web service side. Used the "Access-Control-Allow-Origin" header found here:
https://developer.mozilla.org/En/HTTP_access_control