jQuery POST to webservice via CORS - javascript

I have read a lot of topics about CORS & Javascript and about changing the headers in your post but I can't find the right example I am looking for.
So I'm going to first up start with explaining the situation:
I can not change anything to the webserver since this is out of my reach (It's a SAP Cloud Portal)
I can only change the POST code, so I can only control what I send.
The problem I have is described in the following Post:
jQuery $.ajax(), $.post sending "OPTIONS" as REQUEST_METHOD in Firefox
--> My FF & Chrome Headers send a METHOD OPTIONS instead of METHOD POST.
I have written example code that works in IE but not in FF & Chrome:
var dataString = "<result><firstname>example</firstname><lastname>ThisIsSparta</lastname></result>";
var urlString = "http://delyo001.you.local:8000/sap/bc/youconsulting/ws/rest/anonymous/z_names_post";
//Add TO SAP.
var aData =
jQuery.ajax({
type: "POST",
contentType: "application/xml",
url: urlString, // for different servers cross-domain restrictions need to be handled
data: dataString,
dataType: "text",
success: function(xml) { // callback called when data is received
//oModel.setData(data); // fill the received data into the JSONModel
alert("success to post");
},
error: function(xml) { // callback called when data is received
//oModel.setData(data); // fill the received data into the JSONModel
alert("fail to post");
}
});
});
Or
var invocation = new XMLHttpRequest();
var url = 'http://delyo001.you.local:8000/sap/bc/youconsulting/ws/rest/anonymous/z_names_post';
var body = '<result><firstname>perthyrtyrtygop</firstname><lastname>sparta</lastname></result>';
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.send(body);
I have found 2 ways to fix this but without any examples:
- do something with a proxy?
- send specific headers
More information about my problem can be found at:
- http://scn.sap.com/message/13697625#13697625

If you can't set the right headers on the server-side and you can't modify the response for jsonP you should indeed use a proxy.
A proxy script is a sort of middleware. You make a request to the script the script gets the data, and returns it to you. For example php proxy. You can make the same thing in asp, jsp, flash or even java applet.
Now you have your SAP service, a proxy (php)file in a your prefered location, and your local javascript in the same domain as the proxy. You don't even need CORS.
If you want to put the proxy in another domain you have to make sure the php file sends the right headers. (Access-Control-Allow-Origin yourdomain or Access-Control-Allow-Origin * for allow all)

Related

Failed posting data with axios [duplicate]

I'm trying to load a cross-domain HTML page using AJAX but unless the dataType is "jsonp" I can't get a response. However using jsonp the browser is expecting a script mime type but is receiving "text/html".
My code for the request is:
$.ajax({
type: "GET",
url: "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P#ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute",
dataType: "jsonp",
}).success( function( data ) {
$( 'div.ajax-field' ).html( data );
});
Is there any way of avoiding using jsonp for the request? I've already tried using the crossDomain parameter but it didn't work.
If not is there any way of receiving the html content in jsonp? Currently the console is saying "unexpected <" in the jsonp reply.
jQuery Ajax Notes
Due to browser security restrictions, most Ajax requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, port, or protocol.
Script and JSONP requests are not subject to the same origin policy restrictions.
There are some ways to overcome the cross-domain barrier:
CORS Proxy Alternatives
Ways to circumvent the same-origin policy
Breaking The Cross Domain Barrier
There are some plugins that help with cross-domain requests:
Cross Domain AJAX Request with YQL and jQuery
Cross-domain requests with jQuery.ajax
Heads up!
The best way to overcome this problem, is by creating your own proxy in the back-end, so that your proxy will point to the services in other domains, because in the back-end not exists the same origin policy restriction. But if you can't do that in back-end, then pay attention to the following tips.
**Warning!**
Using third-party proxies is not a secure practice, because they can keep track of your data, so it can be used with public information, but never with private data.
The code examples shown below use jQuery.get() and jQuery.getJSON(), both are shorthand methods of jQuery.ajax()
CORS Anywhere
2021 Update
Public demo server (cors-anywhere.herokuapp.com) will be very limited by January 2021, 31st
The demo server of CORS Anywhere (cors-anywhere.herokuapp.com) is meant to be a demo of this project. But abuse has become so common that the platform where the demo is hosted (Heroku) has asked me to shut down the server, despite efforts to counter the abuse. Downtime becomes increasingly frequent due to abuse and its popularity.
To counter this, I will make the following changes:
The rate limit will decrease from 200 per hour to 50 per hour.
By January 31st, 2021, cors-anywhere.herokuapp.com will stop serving as an open proxy.
From February 1st. 2021, cors-anywhere.herokuapp.com will only serve requests after the visitor has completed a challenge: The user (developer) must visit a page at cors-anywhere.herokuapp.com to temporarily unlock the demo for their browser. This allows developers to try out the functionality, to help with deciding on self-hosting or looking for alternatives.
CORS Anywhere is a node.js proxy which adds CORS headers to the proxied request.
To use the API, just prefix the URL with the API URL. (Supports https: see github repository)
If you want to automatically enable cross-domain requests when needed, use the following snippet:
$.ajaxPrefilter( function (options) {
if (options.crossDomain && jQuery.support.cors) {
var http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
options.url = http + '//cors-anywhere.herokuapp.com/' + options.url;
//options.url = "http://cors.corsproxy.io/url=" + options.url;
}
});
$.get(
'http://en.wikipedia.org/wiki/Cross-origin_resource_sharing',
function (response) {
console.log("> ", response);
$("#viewer").html(response);
});
Whatever Origin
Whatever Origin is a cross domain jsonp access. This is an open source alternative to anyorigin.com.
To fetch the data from google.com, you can use this snippet:
// It is good specify the charset you expect.
// You can use the charset you want instead of utf-8.
// See details for scriptCharset and contentType options:
// http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings
$.ajaxSetup({
scriptCharset: "utf-8", //or "ISO-8859-1"
contentType: "application/json; charset=utf-8"
});
$.getJSON('http://whateverorigin.org/get?url=' +
encodeURIComponent('http://google.com') + '&callback=?',
function (data) {
console.log("> ", data);
//If the expected response is text/plain
$("#viewer").html(data.contents);
//If the expected response is JSON
//var response = $.parseJSON(data.contents);
});
CORS Proxy
CORS Proxy is a simple node.js proxy to enable CORS request for any website.
It allows javascript code on your site to access resources on other domains that would normally be blocked due to the same-origin policy.
CORS-Proxy gr2m (archived)
CORS-Proxy rmadhuram
How does it work?
CORS Proxy takes advantage of Cross-Origin Resource Sharing, which is a feature that was added along with HTML 5. Servers can specify that they want browsers to allow other websites to request resources they host. CORS Proxy is simply an HTTP Proxy that adds a header to responses saying "anyone can request this".
This is another way to achieve the goal (see www.corsproxy.com). All you have to do is strip http:// and www. from the URL being proxied, and prepend the URL with www.corsproxy.com/
$.get(
'http://www.corsproxy.com/' +
'en.wikipedia.org/wiki/Cross-origin_resource_sharing',
function (response) {
console.log("> ", response);
$("#viewer").html(response);
});
The http://www.corsproxy.com/ domain now appears to be an unsafe/suspicious site. NOT RECOMMENDED TO USE.
CORS proxy browser
Recently I found this one, it involves various security oriented Cross Origin Remote Sharing utilities. But it is a black-box with Flash as backend.
You can see it in action here: CORS proxy browser
Get the source code on GitHub: koto/cors-proxy-browser
You can use Ajax-cross-origin a jQuery plugin.
With this plugin you use jQuery.ajax() cross domain. It uses Google services to achieve this:
The AJAX Cross Origin plugin use Google Apps Script as a proxy jSON
getter where jSONP is not implemented. When you set the crossOrigin
option to true, the plugin replace the original url with the Google
Apps Script address and send it as encoded url parameter. The Google
Apps Script use Google Servers resources to get the remote data, and
return it back to the client as JSONP.
It is very simple to use:
$.ajax({
crossOrigin: true,
url: url,
success: function(data) {
console.log(data);
}
});
You can read more here:
http://www.ajax-cross-origin.com/
If the external site doesn't support JSONP or CORS, your only option is to use a proxy.
Build a script on your server that requests that content, then use jQuery ajax to hit the script on your server.
Just put this in the header of your PHP Page and it ill work without API:
header('Access-Control-Allow-Origin: *'); //allow everybody
or
header('Access-Control-Allow-Origin: http://codesheet.org'); //allow just one domain
or
$http_origin = $_SERVER['HTTP_ORIGIN']; //allow multiple domains
$allowed_domains = array(
'http://codesheet.org',
'http://stackoverflow.com'
);
if (in_array($http_origin, $allowed_domains))
{
header("Access-Control-Allow-Origin: $http_origin");
}
I'm posting this in case someone faces the same problem I am facing right now. I've got a Zebra thermal printer, equipped with the ZebraNet print server, which offers a HTML-based user interface for editing multiple settings, seeing the printer's current status, etc. I need to get the status of the printer, which is displayed in one of those html pages, offered by the ZebraNet server and, for example, alert() a message to the user in the browser. This means that I have to get that html page in Javascript first. Although the printer is within the LAN of the user's PC, that Same Origin Policy is still staying firmly in my way. I tried JSONP, but the server returns html and I haven't found a way to modify its functionality (if I could, I would have already set the magic header Access-control-allow-origin: *). So I decided to write a small console app in C#. It has to be run as Admin to work properly, otherwise it trolls :D an exception. Here is some code:
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
//foreach (string s in prefixes)
//{
// listener.Prefixes.Add(s);
//}
listener.Prefixes.Add("http://*:1234/"); // accept connections from everywhere,
//because the printer is accessible only within the LAN (no portforwarding)
listener.Start();
Console.WriteLine("Listening...");
// Note: The GetContext method blocks while waiting for a request.
HttpListenerContext context;
string urlForRequest = "";
HttpWebRequest requestForPage = null;
HttpWebResponse responseForPage = null;
string responseForPageAsString = "";
while (true)
{
context = listener.GetContext();
HttpListenerRequest request = context.Request;
urlForRequest = request.RawUrl.Substring(1, request.RawUrl.Length - 1); // remove the slash, which separates the portNumber from the arg sent
Console.WriteLine(urlForRequest);
//Request for the html page:
requestForPage = (HttpWebRequest)WebRequest.Create(urlForRequest);
responseForPage = (HttpWebResponse)requestForPage.GetResponse();
responseForPageAsString = new StreamReader(responseForPage.GetResponseStream()).ReadToEnd();
// Obtain a response object.
HttpListenerResponse response = context.Response;
// Send back the response.
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseForPageAsString);
// Get a response stream and write the response to it.
response.ContentLength64 = buffer.Length;
response.AddHeader("Access-Control-Allow-Origin", "*"); // the magic header in action ;-D
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
//listener.Stop();
All the user needs to do is run that console app as Admin. I know it is way too ... frustrating and complicated, but it is sort of a workaround to the Domain Policy problem in case you cannot modify the server in any way.
edit: from js I make a simple ajax call:
$.ajax({
type: 'POST',
url: 'http://LAN_IP:1234/http://google.com',
success: function (data) {
console.log("Success: " + data);
},
error: function (e) {
alert("Error: " + e);
console.log("Error: " + e);
}
});
The html of the requested page is returned and stored in the data variable.
To get the data form external site by passing using a local proxy as suggested by jherax you can create a php page that fetches the content for you from respective external url and than send a get request to that php page.
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost/get_url_content.php',false);
if(req.status == 200) {
alert(req.responseText);
}
as a php proxy you can use https://github.com/cowboy/php-simple-proxy
Your URL doesn't work these days, but your code can be updated with this working solution:
var url = "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P#ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute";
url = 'https://google.com'; // TEST URL
$.get("https://images"+~~(Math.random()*33)+"-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=" + encodeURI(url), function(data) {
$('div.ajax-field').html(data);
});
<div class="ajax-field"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You need CORS proxy which proxies your request from your browser to requested service with appropriate CORS headers. List of such services are in code snippet below. You can also run provided code snippet to see ping to such services from your location.
$('li').each(function() {
var self = this;
ping($(this).text()).then(function(delta) {
console.log($(self).text(), delta, ' ms');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/jdfreder/pingjs/c2190a3649759f2bd8569a72ae2b597b2546c871/ping.js"></script>
<ul>
<li>https://crossorigin.me/</li>
<li>https://cors-anywhere.herokuapp.com/</li>
<li>http://cors.io/</li>
<li>https://cors.5apps.com/?uri=</li>
<li>http://whateverorigin.org/get?url=</li>
<li>https://anyorigin.com/get?url=</li>
<li>http://corsproxy.nodester.com/?src=</li>
<li>https://jsonp.afeld.me/?url=</li>
<li>http://benalman.com/code/projects/php-simple-proxy/ba-simple-proxy.php?url=</li>
</ul>
Figured it out.
Used this instead.
$('.div_class').load('http://en.wikipedia.org/wiki/Cross-origin_resource_sharing #toctitle');

How to implement cross domain access in tomcat when using only jsp and javascript/ajax/jQuery and not using php?

I am developing a GIS Map Java web application using jsp, javascript/ajax/jQuery which is deployed in tomcat server. I need to implement cross-domain access here to get response from google api which return response in json format. But since cross domain access is not possible with xmlhttp, I cant get a response.
I have seen some posts suggesting the use of proxy.php in client side. But I am not using php and I would like to know if there is anyway to implement this using jsp/javascript alone. Is there any special configuration to be set in tomcat?? Kindly help.
Here is what i try to do:
var url = "http://maps.googleapis.com/maps/api/directions/json?origin=26.849307092121,75.781290279188&destination=26.932491611988,75.805420139913&alternatives=true&sensor=false";
xmlhttp.open("GET",url,false);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xmlhttp.send();
function AJAX_addShortestRoute() {
// if(xmlhttp.readyState == 4) {
var response=xmlhttp.responseText;
// document.write(response);
alert(response);
}`
But the request is never processed, since cross-domain access is not possible. Kindly help
Thanks and Regards
Ginger.
I resolved the issue. The only solution for cross domain (which I think) is use cross domain access through proxy server..
Here is how it is done.
var mapsUrl = 'http://maps.googleapis.com/maps/api/directions/json?origin='+source_y+','+source_x+'&destination='+dest_y+','+dest_x+'&alternatives=true&sensor=true';
var encodedUrl = encodeURIComponent(mapsUrl);
var proxyUrl = 'http://jsonp.guffa.com/Proxy.ashx?url=' + encodedUrl;
$.ajax({
url: proxyUrl,
dataType: 'jsonp',
cache: false,
success: function (result) {
//Your code goes here
}
});

Cross-domain Jquery JSONP POST to Rails app

This is killing me. Trying to load data from a different domain from an API-sorts of that I'm trying to write. When sending JSON parameters as POST they get discarded, I've read somewhere that some special headers must be set before_filter:
def cors_headers #set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
headers['Access-Control-Max-Age'] = "1728000"
headers['Access-Control-Allow-Headers'] = 'content-type, accept'
end
Haven't had any luck with these though. Guess it's a browser limitation.
When I try sending the data as GET instead of POST, it gets added to the URL like this:
Completed in 959ms (View: 0, DB: 2) | 200 OK [http://www.somedomain.com/connector/browse/Sport.json?callback=jQuery16105855946165975183_1379526705493&{%22filters%22:[{%22filter%22:{%22attribute%22:%22id%22,%22op
erator%22:%22%3E%22,%22value%22:%222%22}},{%22filter%22:{%22attribute%22:%22id%22,%22operator%22:%22%3C%22,%22value%22:%227523%22}}]}&_=1379526723982]
So Rails basically can't see the filters which are the params that I'm trying to send
Parameters: {"{\"filters\":"=>{}, "id"=>"Sport", "_"=>"1379526723982", "callback"=>"jQuery16105855946165975183_1379526705493"}
The jquery snippet I'm playing with is:
$jq.ajax({url: "http://www.somedomain.com/connector/browse/" + x + ".json" + "?callback=?",
type: "get", // tried post too
dataType: "json", // tried jsonp too
accepts: "json",
data: req_data, // this is JSON.stringified already
processData:false,
contentType: "application/json; charset=UTF-8;",
success: output
});
The sample data I'm trying to send is this
{"filters":[{"filter":{"attribute":"id","operator":">","value":"2"}},{"filter":{"attribute":"id","operator":"<","value":"7523"}}]}
Has anyone an idea on how to sort this out?
Muchos gracias!
Basically the JS SOP prevents us from sending a POST request and reading the response, but this can be worked around like this:
1) Compose the request data, send it as POST. Don’t expect to receive a response. Don’t use on success, use on complete instead. Add a random-ish variable to the request
2) Temporarily store the response on the server side in a file or session variable or memcached server, use the random var mentioned above as key within the store.
3) send a 2nd JSON AJAX call to fetch the cached object.
With memcached, make sure the cached responses get removed from time to time or expire, in my case the app gets a lot of traffic, it would spam my memcache servers with junk if not set to expire.
here's some sample code

Strange $.post() AJAX error when parsing JSON

I am facing this strange error in using $.post.
works
$("#add-video").click(function(){
var url = $("#new-video-url").val();
$('#loader').show();
$.post( base_url + "forms/coach/get_url.php", { url:url, base_url:base_url }, function(data){
alert(data);
$('#loader').hide();
});
});
The above piece of code, shows me the json array I am receiving using a php file, and also shows the title field here, and hides the loader image.
But when I alert(data.title), it shows me undefined. More over, when I add datatype 'json' to $.post,
doesn't work
$("#add-video").click(function(){
var url = $("#new-video-url").val();
$('#loader').show();
$.post( base_url + "forms/coach/get_url.php", { url:url, base_url:base_url }, function(data){
alert(data);
$('#loader').hide();
}, "json"); //Added datatype here.
});
This neither alerts anything nor does it hide the loader image. I also tried,
$("#add-video").click(function(){
var url = $("#new-video-url").val();
$('#loader').show();
$.post( base_url + "forms/coach/get_url.php", { url:url, base_url:base_url }, function(data){
jQuery.parseJSON(data);
alert(data.title);
$('#loader').hide();
});
});
The above one too neither alerts anything nor does it hide the loader. And then I tried this one too that did nothing.
$("#add-video").click(function(){
var url = $("#new-video-url").val();
$('#loader').show();
$.post( base_url + "forms/coach/get_url.php", { url:url, base_url:base_url }, function(data){
jQuery.parseJSON(data); //tried without this too.
alert(data['title']);
$('#loader').hide();
});
});
The strangest thing is that I have previously used json as I have shown in the 2nd script(out of 4), and that works normally. My JS console too doesn't show any errors or warning. What am I doing wrong here? How do I access the title field of data?
If this helps, here is how I send the json array,
$json = array("title" => $title, "embed" => $embed, "desc" => $desc, "duration" => $duration, "date" => $date);
print_r(json_encode($json));
I would really appreciate if someone can point out the error and tell me why my scripts are failing, similar functions worked in other js file.
here is my data, that is returned by server,
{"title":"Sunn Raha Hai Na Tu Aashiqui 2 Full Song With Lyrics |
Aditya Roy Kapur, Shraddha Kapoor","embed":"\r\t\t\t\t\t\r\t\t\t\t\t</param></param>\r\t\t\t\t\t</param>\r\t\t\t\t\t\r\t\t\t\t\t</embed></object>","desc":"Presenting
full song \"Sun Raha Hai Na Tu\" with lyrics from movie \"Aashiqui 2\"
produced by T-Series Films & Vishesh Films, starring Aditya Roy Kapur,
Shraddha Kapoor in voice of Ankit Tiwari. \n\nSong: SUNN RAHA
HAI\nSinger: ANKIT TIWARI\nMusic Director: ANKIT TIWARI\nAssistant Mix
Engineer - MICHAEL EDWIN PILLAI\nMixed and Mastered by ERIC PILLAI
(FUTURE SOUND OF BOMBAY)\nLyrics:SANDEEP NATH\nMovie: AASHIQUI
2\nProducer: BHUSHAN KUMAR KRISHAN KUAMR Producer: MUKESH BHATT
\nDirector: MOHIT SURI\nMusic Label: T-SERIES\n\nBuy from iTunes -
https://itunes.apple.com/in/album/aashiqui-2-original-motion/id630590910?ls=1\n\nEnjoy
& stay connected with us!! \n\nSUBSCRIBE T-Series channel for
unlimited entertainment\nhttp://www.youtube.com/tseries\n\nCircle
us on G+ \nhttp://www.google.com/+tseriesmusic\n\nLike us on
Facebook\nhttp://www.facebook.com/tseriesmusic\n\nFollow
us\nhttp://www.twitter.com/_Tseries","duration":"391","date":"2013-04-03"}
Edit
This worked suddenly.. :o
$("#add-video").click(function(){
var url = $("#new-video-url").val();
$('#loader').show();
$.post( base_url + "forms/coach/get_url.php", { url:url, base_url:base_url }, function(data){
alert(data.desc);
console.log(data.desc);
$("#loader").hide();
}, "json");
});
In comments, you mention that this AJAX corresponds to a YouTube API.
YouTube's blog announced in 2012 that they would support CORS, which uses server-side header flags that compatible browsers interpret as permitting requests that would otherwise be prohibited by browser security Same-Origin-Policy.
Assuming, as you say, the first example worked, the first issue was "Why did (a subsequent) alert(data.title) fail? (my edit) ". If you type alert(data.title) in the console, it will fail because the scope of data is the callback function where it is defined as a parameter, and in the global scope data is undefined. If you try to pass data back to the global scope somehow, it can still be undefined because $.post returns immediately, before the data has been fetched, and merely queues a request and sets the callback function you supply to handle the reply.
The second example, which explicitly sets the $.post dataType parameter to 'json', may fail with CORS based API because the mime types for json are not allowed to be sent up to the server as Content-Type: for a simple CORS request, and $.post will as far as I know only do simple requests without preflight. $.ajax can possibly do the more complex requests if correctly applied.
The work around to keep using $.post is not to use json as the expected data type, send requests up as form data, the server may send you back json anyway if that is what the API says will happen, which can be verified while testing the code.
From https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Simple requests
A simple cross-site request is one that:
Only uses GET, HEAD or POST.
If POST is used to send data to the
server, the Content-Type of the data sent to the server with the HTTP
POST request is one of application/x-www-form-urlencoded,
multipart/form-data, or text/plain.
Notice that application/json did not make the list of what Content-Type is permissible in a simple CORS request.
See also A CORS POST request works from plain javascript, but why not with jQuery?
Use ajax as
$.ajax({
url:url,
type:'post',
dataType:'json',
success:callback
})
With this type you can set lots of parameter in low level.
With datatype attribute jQuery parses JSON and send data as callback function.
I think you have to replace all single \ with double '\' to feed it to JSON.parse.

How do I send a cross-domain POST request via JavaScript?

How do I send a cross-domain POST request via JavaScript?
Notes - it shouldn't refresh the page, and I need to grab and parse the response afterwards.
Update: Before continuing everyone should read and understand the web.dev tutorial on CORS. It is easy to understand and very clear.
If you control the server being POSTed, simply leverage the "Cross-Origin Resource Sharing standard" by setting response headers on the server. This answer is discussed in other answers in this thread, but not very clearly in my opinion.
In short here is how you accomplish the cross domain POST from from.com/1.html to to.com/postHere.php (using PHP as an example). Note: you only need to set Access-Control-Allow-Origin for NON OPTIONS requests - this example always sets all headers for a smaller code snippet.
In postHere.php setup the following:
switch ($_SERVER['HTTP_ORIGIN']) {
case 'http://from.com': case 'https://from.com':
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
break;
}
This allows your script to make cross domain POST, GET and OPTIONS. This will become clear as you continue to read...
Setup your cross domain POST from JS (jQuery example):
$.ajax({
type: 'POST',
url: 'https://to.com/postHere.php',
crossDomain: true,
data: '{"some":"json"}',
dataType: 'json',
success: function(responseData, textStatus, jqXHR) {
var value = responseData.someKey;
},
error: function (responseData, textStatus, errorThrown) {
alert('POST failed.');
}
});
When you do the POST in step 2, your browser will send a "OPTIONS" method to the server. This is a "sniff" by the browser to see if the server is cool with you POSTing to it. The server responds with an "Access-Control-Allow-Origin" telling the browser its OK to POST|GET|ORIGIN if request originated from "http://from.com" or "https://from.com". Since the server is OK with it, the browser will make a 2nd request (this time a POST). It is good practice to have your client set the content type it is sending - so you'll need to allow that as well.
MDN has a great write-up about HTTP access control, that goes into detail of how the entire flow works. According to their docs, it should "work in browsers that support cross-site XMLHttpRequest". This is a bit misleading however, as I THINK only modern browsers allow cross domain POST. I have only verified this works with safari,chrome,FF 3.6.
Keep in mind the following if you do this:
Your server will have to handle 2 requests per operation
You will have to think about the security implications. Be careful before doing something like 'Access-Control-Allow-Origin: *'
This wont work on mobile browsers. In my experience they do not allow cross domain POST at all. I've tested android, iPad, iPhone
There is a pretty big bug in FF < 3.6 where if the server returns a non 400 response code AND there is a response body (validation errors for example), FF 3.6 wont get the response body. This is a huge pain in the ass, since you cant use good REST practices. See bug here (its filed under jQuery, but my guess is its a FF bug - seems to be fixed in FF4).
Always return the headers above, not just on OPTION requests. FF needs it in the response from the POST.
If you control the remote server, you should probably use CORS, as described in this answer; it's supported in IE8 and up, and all recent versions of FF, GC, and Safari. (But in IE8 and 9, CORS won't allow you to send cookies in the request.)
So, if you don't control the remote server, or if you have to support IE7, or if you need cookies and you have to support IE8/9, you'll probably want to use an iframe technique.
Create an iframe with a unique name. (iframes use a global namespace for the entire browser, so pick a name that no other website will use.)
Construct a form with hidden inputs, targeting the iframe.
Submit the form.
Here's sample code; I tested it on IE6, IE7, IE8, IE9, FF4, GC11, S5.
function crossDomainPost() {
// Add the iframe with a unique name
var iframe = document.createElement("iframe");
var uniqueString = "CHANGE_THIS_TO_SOME_UNIQUE_STRING";
document.body.appendChild(iframe);
iframe.style.display = "none";
iframe.contentWindow.name = uniqueString;
// construct a form with hidden inputs, targeting the iframe
var form = document.createElement("form");
form.target = uniqueString;
form.action = "http://INSERT_YOUR_URL_HERE";
form.method = "POST";
// repeat for each parameter
var input = document.createElement("input");
input.type = "hidden";
input.name = "INSERT_YOUR_PARAMETER_NAME_HERE";
input.value = "INSERT_YOUR_PARAMETER_VALUE_HERE";
form.appendChild(input);
document.body.appendChild(form);
form.submit();
}
Beware! You won't be able to directly read the response of the POST, since the iframe exists on a separate domain. Frames aren't allowed to communicate with each other from different domains; this is the same-origin policy.
If you control the remote server but you can't use CORS (e.g. because you're on IE8/IE9 and you need to use cookies), there are ways to work around the same-origin policy, for example by using window.postMessage and/or one of a number of libraries allowing you to send cross-domain cross-frame messages in older browsers:
Porthole
XSSInterface
EasyXDM
jQuery PostMessage Plugin
If you don't control the remote server, then you can't read the response of the POST, period. It would cause security problems otherwise.
Create an iFrame,
put a form in it with Hidden inputs,
set the form's action to the URL,
Add iframe to document
submit the form
Pseudocode
var ifr = document.createElement('iframe');
var frm = document.createElement('form');
frm.setAttribute("action", "yoururl");
frm.setAttribute("method", "post");
// create hidden inputs, add them
// not shown, but similar (create, setAttribute, appendChild)
ifr.appendChild(frm);
document.body.appendChild(ifr);
frm.submit();
You probably want to style the iframe, to be hidden and absolutely positioned. Not sure cross site posting will be allowed by the browser, but if so, this is how to do it.
Keep it simple:
cross-domain POST:
use crossDomain: true,
shouldn't refresh the page:
No, it will not refresh the page as the success or error async callback will be called when the server send back the response.
Example script:
$.ajax({
type: "POST",
url: "http://www.yoururl.com/",
crossDomain: true,
data: 'param1=value1&param2=value2',
success: function (data) {
// do something with server response data
},
error: function (err) {
// handle your error logic here
}
});
If you have access to all servers involved, put the following in the header of the reply for the page being requested in the other domain:
PHP:
header('Access-Control-Allow-Origin: *');
For example, in Drupal's xmlrpc.php code you would do this:
function xmlrpc_server_output($xml) {
$xml = '<?xml version="1.0"?>'."\n". $xml;
header('Connection: close');
header('Content-Length: '. strlen($xml));
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/x-www-form-urlencoded');
header('Date: '. date('r'));
// $xml = str_replace("\n", " ", $xml);
echo $xml;
exit;
}
This probably creates a security problem, and you should make sure that you take the appropriate measures to verify the request.
Check the post_method function in http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - a good example for the iframe method described above.
Create two hidden iframes (add "display: none;" to the css style). Make your second iframe point to something on your own domain.
Create a hidden form, set its method to "post" with target = your first iframe, and optionally set enctype to "multipart/form-data" (I'm thinking you want to do POST because you want to send multipart data like pictures?)
When ready, make the form submit() the POST.
If you can get the other domain to return javascript that will do Cross-Domain Communication With Iframes (http://softwareas.com/cross-domain-communication-with-iframes) then you are in luck, and you can capture the response as well.
Of course, if you want to use your server as a proxy, you can avoid all this. Simply submit the form to your own server, which will proxy the request to the other server (assuming the other server isn't set up to notice IP discrepancies), get the response, and return whatever you like.
One more important thing to note!!!
In example above it's described how to use
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 and lower has a bug with cross-domain XHR.
According to Firebug no requests except OPTIONS were sent. No POST. At all.
Spent 5 hours testing/tuning my code. Adding a lot of headers on the remote server (script). Without any effect.
But later, I've updated JQuery lib to 1.6.4, and everything works like a charm.
If you want to do this in ASP.net MVC environment with JQuery AJAX, follow these steps:
(this is a summary of the solution offered at this thread)
Assume that "caller.com"(can be any website) needs to post to "server.com"(an ASP.net MVC application)
On the "server.com" app's Web.config add the following section:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
</customHeaders>
</httpProtocol>
On the "server.com", we'll have the following action on the controller(called "Home") to which we will be posting:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Then from the "caller.com", post data from a form(with the html id "formId") to "server.com" as follow:
$.ajax({
type: "POST",
url: "http://www.server.com/home/save",
dataType: 'json',
crossDomain: true,
data: $(formId).serialize(),
success: function (jsonResult) {
//do what ever with the reply
},
error: function (jqXHR, textStatus) {
//handle error
}
});
There is one more way (using html5 feature). You can use proxy iframe hosted on that other domain, you send message using postMessage to that iframe, then that iframe can do POST request (on same domain) and postMessage back with reposnse to the parent window.
parent on sender.com
var win = $('iframe')[0].contentWindow
function get(event) {
if (event.origin === "http://reciver.com") {
// event.data is response from POST
}
}
if (window.addEventListener){
addEventListener("message", get, false)
} else {
attachEvent("onmessage", get)
}
win.postMessage(JSON.stringify({url: "URL", data: {}}),"http://reciver.com");
iframe on reciver.com
function listener(event) {
if (event.origin === "http://sender.com") {
var data = JSON.parse(event.data);
$.post(data.url, data.data, function(reponse) {
window.parent.postMessage(reponse, "*");
});
}
}
// don't know if we can use jQuery here
if (window.addEventListener){
addEventListener("message", listener, false)
} else {
attachEvent("onmessage", listener)
}
High level.... You need to have a cname setup on your server so that other-serve.your-server.com points to other-server.com.
Your page dynamically creates an invisible iframe, which acts as your transport to other-server.com. You then have to communicate via JS from your page to the other-server.com and have call backs that return the data back to your page.
Possible but requires coordination from your-server.com and other-server.com
I think the best way is to use XMLHttpRequest (e.g. $.ajax(), $.post() in jQuery) with one of Cross-Origin Resource Sharing polyfills https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#wiki-CORS
This is an old question, but some new technology might help someone out.
If you have administrative access to the other server then you can use the opensource Forge project to accomplish your cross-domain POST. Forge provides a cross-domain JavaScript XmlHttpRequest wrapper that takes advantage of Flash's raw socket API. The POST can even be done over TLS.
The reason you need administrative access to the server you are POSTing to is because you must provide a cross-domain policy that permits access from your domain.
http://github.com/digitalbazaar/forge
I know this is an old question, but I wanted to share my approach. I use cURL as a proxy, very easy and consistent. Create a php page called submit.php, and add the following code:
<?
function post($url, $data) {
$header = array("User-Agent: " . $_SERVER["HTTP_USER_AGENT"], "Content-Type: application/x-www-form-urlencoded");
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
$url = "your cross domain request here";
$data = $_SERVER["QUERY_STRING"];
echo(post($url, $data));
Then, in your js (jQuery here):
$.ajax({
type: 'POST',
url: 'submit.php',
crossDomain: true,
data: '{"some":"json"}',
dataType: 'json',
success: function(responseData, textStatus, jqXHR) {
var value = responseData.someKey;
},
error: function (responseData, textStatus, errorThrown) {
alert('POST failed.');
}
});
Should be possible with a YQL custom table + JS XHR, take a look at:
http://developer.yahoo.com/yql/guide/index.html
I use it to do some client side (js) html scraping, works fine
(I have a full audio player, with search on internet/playlists/lyrics/last fm informations, all client js + YQL)
CORS is for you.
CORS is "Cross Origin Resource Sharing", is a way to send cross domain request.Now the XMLHttpRequest2 and Fetch API both support CORS, and it can send both POST and GET request
But it has its limits.Server need to specific claim the Access-Control-Allow-Origin, and it can not be set to '*'.
And if you want any origin can send request to you, you need JSONP (also need to set Access-Control-Allow-Origin, but can be '*')
For lots of request way if you don't know how to choice, I think you need a full functional component to do that.Let me introduce a simple component https://github.com/Joker-Jelly/catta
If you are using modern browser (> IE9, Chrome, FF, Edge, etc.), Very Recommend you to use a simple but beauty component https://github.com/Joker-Jelly/catta.It have no dependence, Less than 3KB, and it support Fetch, AJAX and JSONP with same deadly sample syntax and options.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
It also it support all the way to import to your project, like ES6 module, CommonJS and even <script> in HTML.
If you have access to the cross domain server and don't want to make any code changes on server side, you can use a library called - 'xdomain'.
How it works:
Step 1:
server 1: include the xdomain library and configure the cross domain as a slave:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Step 2:
on cross domain server, create a proxy.html file and include server 1 as a master:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Step 3:
Now, you can make an AJAX call to the proxy.html as endpoint from server1. This is bypass the CORS request. The library internally uses iframe solution which works with Credentials and all possible methods: GET, POST etc.
Query ajax code:
$.ajax({
url: 'https://crossdomain_server/proxy.html',
type: "POST",
data: JSON.stringify(_data),
dataType: "json",
contentType: "application/json; charset=utf-8"
})
.done(_success)
.fail(_failed)

Categories

Resources