Submit cross domain ajax POST request - javascript

I swear I saw an article about this at one point but can not find it...
How can I perform a jQuery ajax request of type POST on another domain? Must be accomplished without a proxy. Is this possible?

Yes you can POST all you want, even $.post() works...but you won't get a response back.
This works, the other domain will get the POST:
$.post("http://othersite.com/somePage.php", { thing: "value" }, function(data) {
//data will always be null
});
But the response, data in the above example, will be null due to the same-origin policy.

All the options I've experimented with:
1) PORK: http://www.schizofreend.nl/Pork.Iframe/Examples/ Creates an iframe and submits the post there, then reads the response. Still requires same base domain per
request (i.e. www.foo.com can request
data from www2.foo.com, but not from
www.google.com) . Also requires you to
fiddle with the document.domain
property, which causes adverse side
effects. And there's a pervasive problem in all the major browsers where reloading the page basically shuffles the cached contents of all iframes on the page if any of them are dynamically written. Your response data will show up in the box where an ad is supposed to be.
2) flxhr: http://flxhr.flensed.com/ Can even be used to mask jQuery's built-in ajax so you don't even notice it. Requires flash though, so iPhone is out
3) jsonp: Doesn't work if you're posting a lot of data. boo.
4) chunked jsonp: When your jsonp request is too big, break the query string up into manageable chunks and send multiple get requests. Reconstruct them on the server. This is helpful but breaks down if you're load balancing users between servers.
5) CORS: http://www.w3.org/TR/cors/ doesn't work in older browsers (IE7, IE6, Firefox 2, etc)
So we currently do the following algorithm:
If request is small enough, use JSONP
If not small enough, but user has flash, use FlXHR
Else use chunked JSONP
Spend one afternoon writing that up and you'll be able to use it for good. Adding CORS to our algorithm might be good for faster iPhone support.

If you have control over the code running at the other domain, just let it return an appropriate Access-Control-Allow-Origin header in the response. See also HTTP Access-Control at MDC.

If you want a fire and forget POST where you don't care about the response then just submit a form to a hidden iframe. This requires a Transitional Doctype.
<form method="POST" action="http://example.com/" target="name_of_iframe">
If you want to parse the response, then using a proxy if the only real option.
If you are desperate, and control the remote site, then you can:
Submit a form as above
Set a cookie in the response (which might be blocked before the iframe could cause the cookie to be considered '3rd party' (i.e. likely to be advertising tracking).
Wait long enough for the response to come back
Dynamically generate a script element with the src pointing to the remote site
Use JSON-P in the response and take advantage of the data previously stored in the cookie
This approach is subject to race conditions and generally ugly. Proxing the data through the current domain is a much better approach.

If you need to know that the POST was successful, and don't have control over the remote server:
$.ajax({
type:"POST",
url:"http://www.somesite.com/submit",
data:'firstname=test&lastname=person&email=test#test.com',
complete: function(response){
if(response.status == 0 && response.statusText == "success")
{
/* CORS POST was successful */
}
else
{
/* Show error message */
}
}
});
If there was a problem with the submission then response.statusText should equal "error".
Note: some remote servers will send the HTTP header Access-Control-Allow-Origin: *, which will result in a 200 OK HTTP status code response. In that case, ajax will execute the success handler, and this method is not needed. To look at the response just do console.log(JSON.stringify(response)); or use FireBug's 'Net' panel.

Related

AJAX request gets "No 'Access-Control-Allow-Origin' header is present on the requested resource" error

I attempt to send a GET request in a jQuery AJAX request.
$.ajax({
type: 'GET',
url: /* <the link as string> */,
dataType: 'text/html',
success: function() { alert("Success"); },
error: function() { alert("Error"); },
});
However, whatever I've tried, I got XMLHttpRequest cannot load <page>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:7776' is therefore not allowed access.
I tried everything, from adding header : {} definitions to the AJAX request to setting dataType to JSONP, or even text/plain, using simple AJAX instead of jQuery, even downloading a plugin that enables CORS - but nothing could help.
And the same happens if I attempt to reach any other sites.
Any ideas for a proper and simple solution? Is there any at all?
This is by design. You can't make an arbitrary HTTP request to another server using XMLHttpRequest unless that server allows it by putting out an Access-Control-Allow-Origin header for the requesting host.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
You could retrieve it in a script tag (there isn't the same restriction on scripts and images and stylesheets), but unless the content returned is a script, it won't do you much good.
Here's a tutorial on CORS:
http://www.bennadel.com/blog/2327-cross-origin-resource-sharing-cors-ajax-requests-between-jquery-and-node-js.htm
This is all done to protect the end user. Assuming that an image is actually an image, a stylesheet is just a stylesheet and a script is just a script, requesting those resources from another server can't really do any harm.
But in general, cross-origin requests can do really bad things. Say that you, Zoltan, are using coolsharks.com. Say also that you are logged into mybank.com and there is a cookie for mybank.com in your browser. Now, suppose that coolsharks.com sends an AJAX request to mybank.com, asking to transfer all your money into another account. Because you have a mybank.com cookie stored, they successfully complete the request. And all of this happens without your knowledge, because no page reload occurred. This is the danger of allowing general cross-site AJAX requests.
If you want to perform cross-site requests, you have two options:
Get the server you are making the request to to either
a. Admit you by putting out a Access-Control-Allow-Origin header that includes you (or *)
b. Provide you with a JSONP API.
or
Write your own browser that doesn't follow the standards and has no restrictions.
In (1), you must have the cooperation of the server you are making requests to, and in (2), you must have control over the end user's browser. If you can't fulfill (1) or (2), you're pretty much out of luck.
However, there is a third option (pointed out by charlietfl). You can make the request from a server that you do control and then pass the result back to your page. E.g.
<script>
$.ajax({
type: 'GET',
url: '/proxyAjax.php?url=http%3A%2F%2Fstackoverflow.com%2F10m',
dataType: 'text/html',
success: function() { alert("Success"); },
error: function() { alert("Error"); }
});
</script>
And then on your server, at its most simple:
<?php
// proxyAjax.php
// ... validation of params
// and checking of url against whitelist would happen here ...
// assume that $url now contains "http://stackoverflow.com/10m"
echo file_get_contents($url);
Of course, this method may run into other issues:
Does the site you are a proxy for require the correct referrer or a certain IP address?
Do cookies need to be passed through to the target server?
Does your whitelist sufficiently protect you from making arbitrary requests?
Which headers (e.g. modify time, etc) will you be passing back to the browser as your server received them and which ones will you omit or change?
Will your server be implicated as having made a request that was unlawful (since you are acting as a proxy)?
I'm sure there are others. But if none of those issues prevent it, this third method could work quite well.
you can ask the developers of that domain if they would set the appropriate header for you, this restriction is only for javascript, basically you can request the ressource from your server with php or whatever and the javascript requests the data from your domain then
Old question, but I'm not seeing this solution, which worked for me, anywhere. So hoping this can be helpful for someone.
First, remember that it makes no sense to try modifying the headers of the request to get around a cross-origin resource request. If that were all it took, it would be easy for malicious users to then circumvent this security measure.
Cross-origin requests in this context are only possible if the partner site's server allows it through their response headers.
I got this to work in Django without any CORS middleware by setting the following headers on the response:
response["Access-Control-Allow-Origin"] = "requesting_site.com"
response["Access-Control-Allow-Methods"] = "GET"
response["Access-Control-Allow-Headers"] = "requesting_site.com"
Most answers on here seem to mention the first one, but not the second two. I've just confirmed they are all required. You'll want to modify as needed for your framework or request method (GET, POST, OPTION).
p.s. You can try "*" instead of "requesting_site.com" for initial development just to get it working, but it would be a security hole to allow every site access. Once working, you can restrict it for your requesting site only to make sure you don't have any formatting typos.

React to 303 status code in jquery ( Prevent from redirecting)

when I send requests to a certain server, a 303 response will come, followed by the requested response in combination with a 200 status code.
Funny thing is that I only see this on my developer console's network view. When checking the statuscode and response of my $.ajax() request, there will be the response of the second request, as well as a 200 http status code.
The problem is that it seems that the second request is being cached (though 200 status code), and I really need it to be non-cachable.
Therefore I'd really like to intervene into the forwarding process that occurs with a http 303 status code. I'd like my jquery function to check for the status code, then send the get request with explicit headers, that tell the server not to cache the response.
Well, I just don't know how to do this, since (as mentioned above) the jQuery.ajax method will respond with the forwarded request's response and status code (200).
Can you help me?
edit
10.3.4 303 See Other
The response to the request can be found under a different URI and
SHOULD be retrieved using a GET method on that resource. This method
exists primarily to allow the output of a POST-activated script to
redirect the user agent to a selected resource. The new URI is not a
substitute reference for the originally requested resource. The 303
response MUST NOT be cached, but the response to the second
(redirected) request might be cacheable.
maybe I need to somehow prevent the user agent from redirecting himself, so I can do the redirect?
Or is there a way to simply tell the server/browser not to cache the second request from client-side? or to prevent it from redirecting my request? or at least modify the second request before redirecting?
Responses in the 300 range are meant to be transparent. AFAIK, web browsers don't expose any of them to javascript. Thus, handling the 303 is not an option.
Have you tried setting the cache property to false in the ajaxSetup? It will append a timestamp to the request, preventing the browser from caching the response. You can also do that manually yourself. The browser should match the first request url to the 2nd response
You cannot stop the browser from following the 303 redirect. It sounds like that's not what you want, anyway. Whatever you would do in the browser to prevent the original request from being cached should work equally well for preventing the redirected 200 from being cached. That said, there is little you can do on the browser side other than using a unique URL for each request. This is done for you automatically by jQuery when you set cache: false.
$.ajax({
url: "example.html",
cache: false
}
}).done(function( html ) {
$("#results").append(html);
});
This is old post, but maybe someone will find this useful.
I have the same issue, and in my case the problem was in the method that was called out using the ajax. The problem was in the redirection that was set in the method. So, based on this, you can't use both ajax and redirect(server side), and i removed redirect() function from method, i everything works as expected.
Btw, i am using codeigniter.
See statusCode property of your .ajax() call
Example :
$.ajax({
statusCode: {
303: function() {
alert("page not found");
}
}
});

Receive XML response from Cross-Domain Ajax request with jQuery

I trying to make an ajax request to another domain, it already works, but now I have another problem...
This is my code:
function getChannelMessages(channel) {
jQuery.support.cors = true;
$.ajax(channel, {
cache : true,
type : "get",
data : _channels[channel].request,
global : false,
dataType : "jsonp text xml",
jsonp : false,
success : function jsonpCallback (response) {
console.log(response);
updateChannelRequest(channel);
//getChannelMessages(channel);
}
});
}
As I said, it already works, but the problem is the server returns an XML (Is not my server, is another server from another company - a web service - so I can not change what it returns) and as jsonp expects an json it fails with the error:
SyntaxError: syntax error
<?xml version="1.0"?><ReceiveMessageResponse xmlns="http://q ... />
According to jQuery documentation, adding jsonp text xml should make the magic, converting the response to simple text and then parsing it as XML, but it does not works.
I was already able to make it using YQL, but it has a limit of 10,000 requests per hour, and the system I'm developing will have up to 10 million request per hour. For that same reason, I can not "proxy" in my own server those requests...
FYI: I'm trying to get the newest messages from SQS, so if there is anyway to tell it to return the data as json, it will be easier and better, but I have not find anything either in the documentation...
The plain answer to my question is this: There are only two ways of do this:
Use a proxy. I won't put here all the how-to's to make it, but you can find a lot of information in the web searching for "cors" "cross domains ajax requests" and "yql" (this last is a proxy by Yahoo)
Use CORS. This is Cross-Origin Resource Sharing. That is: activate the server from which you want to get information to sent information to any other domain and to answer to requests from any other domain. To do this you must be the one who manage the server/service.
Those two are the only ways of getting information XML (or any other format) from another domain. To make json cross domain requests:
Use jsonp (Json Padded). I won't explain this (and actually is just extra information since it won't work if the answer from the server is XML - my main problem), cause there is a lot of information on the web.
Unfortunately I was not able to accomplished my goal, cause SQS is not configured to any of this methods... Still, I've got plenty insight of how Cross-Domains Requests works. And I hope this help anyone...

Why Does Public web service return 200 OK but no JSON

I am attempting to call this web service: http://www.civicapps.org/datasets/restaurant-inspections
Here's my code:
<script>
$(document).ready(function() {
function showInspections() {
var data = $.ajax({
type : 'GET',
url : '//api.civicapps.org/restaurant-inspections/',
async : false,
dataType : 'json',
success: function(data){
if(data.status == "ok"){
alert(data);
}
}
});
}
showInspections();
});
</script>
Firebug Net>XHR shows "200 Status OK" and yet there is no response with the JSON data. Likewise, Console tab shows the same GET request and status but the text for it is in red.
Questions:
Am I failing to receive the response data in JSON due to cross-domain issues i.e. the data should be sent in JSONP rather than JSON? If so, is there a way to get around this solely from my end, assuming the response will not be sent in JSONP?
What does the red text in Firebug console indicate?
Am I failing to receive the response data in JSON due to cross-domain issues i.e. the data should be sent in JSONP rather than JSON?
Yes. JSONP is actually very different than "JSON" (i.e. an AJAX request that returns JSON-formatted data). Even though the responses look very similar and the implementation in jQuery is very similar (just add a 'p'!), the actual architecture of JSONP is very different. In fact, JSONP is not even AJAX (if by AJAX you mean something that uses XMLHttpRequest). JSONP gets around cross-domain issues by using a trick involving a dynamically generated <script> element.
If so, is there a way to get around this solely from my end, assuming the response will not be sent in JSONP?
Fortunately, no. While this may be unfortunate for you, it's fortunate for the web. Because if you could get around cross-domain issues from the client side, the web would be far less secure. Imagine you went to my website and some hidden JavaScript downloaded all your new emails from Gmail, parsed them, then sent them to my server. That would be possible if not for the same-origin policy.
JSONP is nice because it offers a workaround for cross-origin requests that services can opt-in to. If a service wants to be accessible cross-domain, then it can be written in JSONP. This prevents unwitting cross-domain services while allowing for services to volunteer cross-domain availability.
What does the red text in Firebug console indicate?
It probably indicates a violation of the same-origin policy.

jQuery.getJSON - Access-Control-Allow-Origin Issue

I'm jusing jQuery's $.getJSON() function to return a short set of JSON data.
I've got the JSON data sitting on a url such as example.com.
I didn't realize it, but as I was accessing that same url, the JSON data couldn't be loaded. I followed through the console and found that XMLHttpRequest couldn't load due to Access-Control-Allow-Origin.
Now, I've read through, a lot of sites that just said to use $.getJSON() and that would be the work around, but obviously it didn't work. Is there something I should change in the headers or in the function?
Help is greatly appreciated.
It's simple, use $.getJSON() function and in your URL just include
callback=?
as a parameter. That will convert the call to JSONP which is necessary to make cross-domain calls. More info: http://api.jquery.com/jQuery.getJSON/
You may well want to use JSON-P instead (see below). First a quick explanation.
The header you've mentioned is from the Cross Origin Resource Sharing standard. Beware that it is not supported by some browsers people actually use, and on other browsers (Microsoft's, sigh) it requires using a special object (XDomainRequest) rather than the standard XMLHttpRequest that jQuery uses. It also requires that you change server-side resources to explicitly allow the other origin (www.xxxx.com).
To get the JSON data you're requesting, you basically have three options:
If possible, you can be maximally-compatible by correcting the location of the files you're loading so they have the same origin as the document you're loading them into. (I assume you must be loading them via Ajax, hence the Same Origin Policy issue showing up.)
Use JSON-P, which isn't subject to the SOP. jQuery has built-in support for it in its ajax call (just set dataType to "jsonp" and jQuery will do all the client-side work). This requires server side changes, but not very big ones; basically whatever you have that's generating the JSON response just looks for a query string parameter called "callback" and wraps the JSON in JavaScript code that would call that function. E.g., if your current JSON response is:
{"weather": "Dreary start but soon brightening into a fine summer day."}
Your script would look for the "callback" query string parameter (let's say that the parameter's value is "jsop123") and wraps that JSON in the syntax for a JavaScript function call:
jsonp123({"weather": "Dreary start but soon brightening into a fine summer day."});
That's it. JSON-P is very broadly compatible (because it works via JavaScript script tags). JSON-P is only for GET, though, not POST (again because it works via script tags).
Use CORS (the mechanism related to the header you quoted). Details in the specification linked above, but basically:
A. The browser will send your server a "preflight" message using the OPTIONS HTTP verb (method). It will contain the various headers it would send with the GET or POST as well as the headers "Origin", "Access-Control-Request-Method" (e.g., GET or POST), and "Access-Control-Request-Headers" (the headers it wants to send).
B. Your PHP decides, based on that information, whether the request is okay and if so responds with the "Access-Control-Allow-Origin", "Access-Control-Allow-Methods", and "Access-Control-Allow-Headers" headers with the values it will allow. You don't send any body (page) with that response.
C. The browser will look at your response and see whether it's allowed to send you the actual GET or POST. If so, it will send that request, again with the "Origin" and various "Access-Control-Request-xyz" headers.
D. Your PHP examines those headers again to make sure they're still okay, and if so responds to the request.
In pseudo-code (I haven't done much PHP, so I'm not trying to do PHP syntax here):
// Find out what the request is asking for
corsOrigin = get_request_header("Origin")
corsMethod = get_request_header("Access-Control-Request-Method")
corsHeaders = get_request_header("Access-Control-Request-Headers")
if corsOrigin is null or "null" {
// Requests from a `file://` path seem to come through without an
// origin or with "null" (literally) as the origin.
// In my case, for testing, I wanted to allow those and so I output
// "*", but you may want to go another way.
corsOrigin = "*"
}
// Decide whether to accept that request with those headers
// If so:
// Respond with headers saying what's allowed (here we're just echoing what they
// asked for, except we may be using "*" [all] instead of the actual origin for
// the "Access-Control-Allow-Origin" one)
set_response_header("Access-Control-Allow-Origin", corsOrigin)
set_response_header("Access-Control-Allow-Methods", corsMethod)
set_response_header("Access-Control-Allow-Headers", corsHeaders)
if the HTTP request method is "OPTIONS" {
// Done, no body in response to OPTIONS
stop
}
// Process the GET or POST here; output the body of the response
Again stressing that this is pseudo-code.

Categories