Post data to JsonP

JavascriptJqueryAjaxJsonJsonp

Javascript Problem Overview


Is it possible to post data to JsonP? Or does all data have to be passed in the querystring as a GET request?

I have alot of data that I need to send to the service, cross domain, and it is too large to send via the querystring

What are the options for getting around this?

Javascript Solutions


Solution 1 - Javascript

It is not possible to do an asynchronous POST to a service on another domain, due to the (quite sensible) limitation of the http://en.wikipedia.org/wiki/Same_origin_policy">same origin policy. JSON-P only works because you're allowed to insert <script> tags into the DOM, and they can point anywhere.

You can, of course, make a page on another domain the action of a regular form POST.

Edit: There are some http://ajaxian.com/archives/how-to-make-xmlhttprequest-calls-to-another-server-in-your-domain">interesting hacks out there if you're willing to go to a lot of effort inserting hidden <iframe>s and mucking about with their properties.

Solution 2 - Javascript

If you need to send a lot of data cross-domain. I usually create a service that you can call in two steps:

  1. First the client do a FORM submit (post allowed cross domain). The service stores the input in the session on the server (using the GUID as key). (the client creates a GUID and send's it as a part of the input)

  2. Then the client do a normal script-inject (JSONP) as a parameter you use the same GUID as you used in the FORM post. The service processes the input from the session and returns the data in the normal JSONP-fashion. After this the session is destroyed.

This of course relies on that you write the server-backend.

Solution 3 - Javascript

I know this is serious necromancy, but I thought I'd post my implementation of JSONP POST using jQuery, which I'm successfully using for my JS widget (this is used for customer registration and login):

Basically, I'm using an IFrame approach, as suggested in the accepted answer. What I'm doing differently is after sending the request, I'm watchin, if the form can be reached in the iframe, using a timer. When the form cannot be reached, it means the request has returned. Then, I'm using a normal JSONP request to query for the status of the operation.

I hope that someone finds it useful. Tested in >=IE8, Chrome, FireFox and Safari.

function JSONPPostForm(form, postUrl, queryStatusUrl, queryStatusSuccessFunc, queryStatusData)
{
	var tmpDiv = $('<div style="display: none;"></div>');
	form.parent().append(tmpDiv);
	var clonedForm = cloneForm(form);
	var iframe = createIFrameWithContent(tmpDiv, clonedForm);

	if (postUrl)
		clonedForm.attr('action', postUrl);

    var postToken = 'JSONPPOST_' + (new Date).getTime();
    clonedForm.attr('id', postToken);
    clonedForm.append('<input name="JSONPPOSTToken" value="'+postToken+'">');
	clonedForm.attr('id', postToken );
	clonedForm.submit();

	var timerId;
	var watchIFrameRedirectHelper = function()
	{
		if (watchIFrameRedirect(iframe, postToken ))
		{
			clearInterval(timerId);
			tmpDiv.remove();
			$.ajax({
				url:  queryStatusUrl,
				data: queryStatusData,
				dataType: "jsonp",
				type: "GET",
				success: queryStatusSuccessFunc
			});
		}
	}

	if (queryStatusUrl && queryStatusSuccessFunc)
		timerId = setInterval(watchIFrameRedirectHelper, 200);
}

function createIFrameWithContent(parent, content)
{
	var iframe = $('<iframe></iframe>');
	parent.append(iframe);

	if (!iframe.contents().find('body').length)
	{
		//For certain IE versions that do not create document content...
		var doc = iframe.contents().get()[0];
		doc.open();
		doc.close();
	}

	iframe.contents().find('body').append(content);
	return iframe;
}

function watchIFrameRedirect(iframe, formId)
{
	try
	{
		if (iframe.contents().find('form[id="' + formId + '"]').length)
			return false;
		else
			return true;
	}
	catch (err)
	{
		return true;
	}
	return false;
}

//This one clones only form, without other HTML markup
function cloneForm(form)
{
    var clonedForm = $('<form></form>');
    //Copy form attributes
    $.each(form.get()[0].attributes, function(i, attr)
    {
        clonedForm.attr(attr.name, attr.value);
    });
    form.find('input, select, textarea').each(function()
    {
        clonedForm.append($(this).clone());
    });

    return clonedForm;
}

Solution 4 - Javascript

Well generally JSONP is implemented by adding a <script> tag to the calling document, such that the URL of the JSONP service is the "src". The browser fetches script source with an HTTP GET transaction.

Now, if your JSONP service is in the same domain as your calling page, then you could probably cobble something together with a simple $.ajax() call. If it's not in the same domain, then I'm not sure how it'd be possible.

Solution 5 - Javascript

You could use a CORS Proxy using this project. It would direct all traffic to an endpoint on your domain and relay that information to an external domain. Since the browser is registering all requests to be on the same domain we are able to post JSON. NOTE: This also works with SSL certificates held on the server.

Solution 6 - Javascript

There's a (hack) solution I've did it many times, you'll be able to Post with JsonP. (You'll be able to Post Form, bigger than 2000 char than you can use by GET)

Client application Javascript

$.ajax({
  type: "POST", // you request will be a post request
  data: postData, // javascript object with all my params
  url: COMAPIURL, // my backoffice comunication api url
  dataType: "jsonp", // datatype can be json or jsonp
  success: function(result){
	console.dir(result);
  }
});

JAVA:

response.addHeader( "Access-Control-Allow-Origin", "*" ); // open your api to any client 
response.addHeader( "Access-Control-Allow-Methods", "POST" ); // a allow post
response.addHeader( "Access-Control-Max-Age", "1000" ); // time from request to response before timeout

PHP:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');

Doing like this, you are opening your server to any post request, you should re-secure this by providing ident or something else.

With this method, you could also change the request type from jsonp to json, both work, just set the right response content type

jsonp

response.setContentType( "text/javascript; charset=utf-8" );

json

response.setContentType( "application/json; charset=utf-8" );

Please not that you're server will no more respect the SOP (same origin policy), but who cares ?

Solution 7 - Javascript

It is possible, here is my solution:

In your javascript:

jQuery.post("url.php",data).complete(function(data) {
    eval(data.responseText.trim()); 
});
function handleRequest(data){
    ....
}

In your url.php:

echo "handleRequest(".$responseData.")";

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChrisCaView Question on Stackoverflow
Solution 1 - JavascriptfriedoView Answer on Stackoverflow
Solution 2 - JavascriptPerView Answer on Stackoverflow
Solution 3 - JavascriptW.B.View Answer on Stackoverflow
Solution 4 - JavascriptPointyView Answer on Stackoverflow
Solution 5 - JavascriptEugene ScrayView Answer on Stackoverflow
Solution 6 - JavascriptDimitri KopriwaView Answer on Stackoverflow
Solution 7 - JavascriptnosemajView Answer on Stackoverflow