Passing Odata Query Options in the Request Body - asp.net-web-api

In the Odata 4.01 URL conventions it says that for GET requests with extremely long filter expressions you can append /$query to the resource path of the URL, use the POST verb instead of GET, and pass the query options part of the URL in the request body. If I try that with my service I get back a 404.
Does the /$query endpoint need to be manually created in the back end or is this something odata is supposed to take care of transparently? I've been searching like crazy but I'm having trouble finding anything about how to implement this.

To support this you add app.UseODataQueryRequest() to your startup somewhere before app.UseRouting()
The framework then transforms ~/$query POST requests into GET requests which are handled by the HttpGet action methods on your controller (source).
Documentation is here (although currently not up to date)
For a complete sample have a look here

One way to avoid this is wrapping the request in a batch request
You can resolve long url with $batch query.
Good post from Hassan Habib https://devblogs.microsoft.com/odata/all-in-one-with-odata-batch//
All what you should do is:
Allow batching in Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseODataBatching(); <---- (1)
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.Select().Filter().Expand().OrderBy();
endpoints.MapODataRoute(
routeName: "api",
routePrefix: "api",
model: GetEdmModel(),
batchHandler: new DefaultODataBatchHandler()); <---- (2)
});
}
Request batch query with body, that contains long url request
POST http://localhost/api/$batch
Content-Type: multipart/mixed; boundary=batch_mybatch
body:
--batch_mybatch
Content-Type: application/http
Content-Transfer-Encoding: binary
GET http://localhost/api/students/735b6ae6-485e-4ad8-a993-36227ac82851 HTTP/1.1 <--long url requst
OData-Version: 4.0
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services
--batch_mybatch

Related

How do I interpret this header in this curl request?

I'm looking at a curl request that has the following as its header. What does this mean?
curl -H 'Authorization:token token="[SOME_VALUE]"' 'https://myurl.com'
Furthermore I'm trying to use RestClient to request this URL from ruby. https://github.com/rest-client/rest-client
Normally in headers it's just a key:value, but here this seems different.
It looks like the API you want to use is adopting the HTTP Token authentication RFC.
This document was a draft and it never turned into an official standard, but there are some APIs that are using it.
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Token token="h480djs93hd8",
coverage="base",
timestamp="137131200",
nonce="dj83hs9s",
auth="djosJKDKJSD8743243/jdk33klY="
You can pass custom headers to RestClient using the header option.
api_token = "xyz"
RestClient.get "http://example.com/resource", { :Authorization => %Q{token token="#{api_token}"} }
I used %Q to allow interpolation. If it's unclear to you, you can also use something like
api_token = "xyz"
RestClient.get "http://example.com/resource", { :Authorization => 'token token="%s"' % api_token }
It will be same as key value pair. Here the key is Authorization and the value is token token="[SOME_VALUE]". That should be something like below as ruby hash copied from here.
{:Authorization => 'token token="[SOME_VALUE]"'}
You can use some additional information in headers, not just key:value. For example:
Accept: text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c
Authorization:token token="[SOME_VALUE]" can be used with API with token based authentication.
Token based authentication is when an API client uses a token identifier to make authenticated HTTP requests.
You can read more about this type of authentication here: http://blog.codeschool.io/2014/02/03/token-based-authentication-rails/

Google Plus API Insert Moments not displayed

I am using C# code to insert moments on User's Wall(It will be displayed in user's app's wall) but those are not being actually inserted. I am getting 200 response after insertion but that response has only 2 fields(kind & id) and no other fields(item, target etc.). I have read most of resources over internet but I think I am only soul who is facing this strange error.
I am pasting here plain http request-response
Request
POST https://www.googleapis.com/plus/v1/people/me/moments/vault HTTP/1.1
User-Agent: google-api-dotnet-client/1.9.1.12394 (gzip)
Authorization: Bearer <accesstoken>
Content-Type: application/json; charset=utf-8
Host: www.googleapis.com
Content-Length: 211
Accept-Encoding: gzip, deflate
{
"target":
{
"name":"An example of add activity",
"url":"https://developers.google.com/+/web/snippet/examples/widget"
},
"type":"http://schemas.google.com/AddActivity"
}
Response 200 OK
{
"kind": "plus#moment",
"id": "Eg0xNDM3OTEwNzAwNDE2GPnkj6mg5b7Y7QEpg7DYUmwWVocyAhAUQgYYlcTmsSI"
}
Important Things
My access_token is already generated by sending parameter request_visible_actions=http://schemas.google.com/AddActivity in auth url.
I am sending useremail and profile scope along with google plus login scope
Can somebody help me??
PS: One strange thing, I have seen that if I don't give "target.url" then I get "500 Internal Server Error"
I have exactly same problem!
I get 200 Ok response with the following data:
{ kind: 'plus#moment',
id: 'Eg0xNDM5ODAzNjQxNDE5GJL-wuqxjM_1FSm5JPhBE8KPMjICEBRCBxiH8r2wphs' }
and then I try to list moments and get 200 Ok response with data:
{ kind: 'plus#momentsFeed',
etag: '"gLJf7LwN3wOpLHXk4IeQ9ES9mEc/6vRErVzx-PXyvghY9zcdoSrT-XU"',
selfLink: 'https://www.googleapis.com/plus/v1/people/101579422490714750738/moments/vault',
title: 'Plus Moments Feed',
updated: '2015-08-17T09:27:21.500Z',
items: [] }
No moments or posts seen in my Google+ feed!!
Seems like this API does not work......
Any ideas? I've read the Indexing API is a replaceent, however I need my Web application to post moments on behalf of User, not android app.

REST method's won't PUT or POST to the server

I'm trying to get some REST methods working in my Spring app but seem to be running into little success. I'm obviously missing something but I can't tell for the life of me what it would be. Here is my controller:
#Controller
public class IndexController {
static Logger log = Logger.getLogger(IndexController.class);
#Autowired
private ProvisionService provisionService;
#RequestMapping(value="/home/data", method=RequestMethod.GET,
headers="Accept=application/json")
public #ResponseBody List<Provision> getData() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = null;
if(principal instanceof UserDetails)
username = ((UserDetails)principal).getUsername();
return provisionService.getAllByUser(username);
}
//JSON put request - doesn't work currently
#RequestMapping(value="/home/data", method=RequestMethod.PUT,
headers="Content-Type=application/json")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateProvisions(#RequestBody List<Provision> provisions) {
log.info("Provisions: " + provisions.toString());
}
#RequestMapping(value={"/","/home"}, method=RequestMethod.GET)
public void showIndex() {}
}
Here is the main part of JSP that utilizes it:
<sf:form id="homeForm" method="put" action="${homeData_url}"></sf:form>
The form is submitted through Javascript when the user clicks on a button. Anyway, things work fine for the GET. I get Json returned with my List of objects, no problems. I then display that using Dojo and so far so good. However, when I try to return the Json with this form I'm getting a 405 - Request method 'POST' not supported error. As you can see I've got the method handler in my Controller so I'm really not sure what I'm doing wrong. I've taken those handler's out of the Spring in Action 3 book and it also resembles what some Spring docs and stuff say to do, but obviously I'm missing a key component. Anyone have any thoughts?
I do have the HiddenHttpMethodFilter mapped in my web.xml which is why I'm using the Spring form tag.
Anyway, any thoughts or help are appreciated. Thank you.
------------------UPDATE------------------
Here are the headers after I click on the button and get the 405 error, if it helps:
http://localhost:8080/NFI/home
POST /NFI/home HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
DNT: 1
Connection: keep-alive
Referer: http://localhost:8080/NFI/home
Cookie: JSESSIONID=584AC21ADE4F214904B9E7E2370363EF
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
HTTP/1.1 405 Method Not Allowed
Server: Apache-Coyote/1.1
Allow: GET, PUT
Content-Type: text/html;charset=utf-8
Content-Length: 1085
Date: Fri, 21 Oct 2011 15:39:26 GMT
Submitting a Form is done using POST. You get a "POST" not supported error.
Above, I see you are using a RequestMethod.PUT in your source code. There's no mention of POST at all.
Add you need to add a parameter _method with value PUT to your request. Not to the json content!
So in the first step I would change requested URL to /home/data?_method=PUT.
If this work you can search for an way how to add the _method parameter to the request content without disturbing the Json data.
You updated your question with the headers, could you also put the entire request out there (actual dumped values) to see the _method parameter(s) being sent?
Also, while I guess the headers=""-rules are valid they shouldn't be needed. You have a json converter bean that will do marshall and unmarshall based on content-type and accept headers, if no valid converter is found Spring will return an error.
The only reason to include it in the #RequestMapping would be if you had a method that actually did something else if you called it with xml instead of json and that sounds like a bad design.
Remove those header-rules and try again, make it as simple as possible and gradually add logic.

Problem with Spring 3 + JSON : HTTP status 406?

I'm trying to get a list of Cities by sending the State name through Ajax in my SpringMVC 3.0 project.
For the purpose, I've used the following call (using jQuery) in my JSP:
<script type="text/javascript">
function getCities() {
jq(function() {
jq.post("getCities.html",
{ stateSelect: jq("#stateSelect").val()},
function(data){
jq("#cities").replaceWith('<span id="cities">Testing</span>');
});
});
}
</script>
And here's my Controller code:
#RequestMapping(value = "/getCities", method = RequestMethod.POST)
public #ResponseBody List<StateNames> getCities(#RequestParam(value="stateSelect", required=true) String stateName,
Model model) {
// Delegate to service to do the actual adding
List<StateNames> listStates = myService.listCityNames(stateName);
// #ResponseBody will automatically convert the returned value into JSON format
// You must have Jackson in your classpath
return listStates;
}
But I get HTTP 406 error stating the following when i run it:
406 Not Acceptable
The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.
I've used Jackson in my Maven dependencies & have defined in my context file.
I've googled extensively & I guess the problem is #ResponseBody is not automatically converting my List to appropriate JSON object.
My Firebug says:
Response Headers
Server Apache-Coyote/1.1
Content-Type text/html;charset=utf-8
Content-Length 1070
Date Sat, 12 Feb 2011 13:09:44 GMT
Request Headers
Host localhost:8080
User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13
Accept */*
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Content-Type application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With XMLHttpRequest
Referer http://localhost:8080/MyApplication/
Content-Length 17
Cookie JSESSIONID=640868A479C40792F8AB3DE118AF12E0
Pragma no-cache
Cache-Control no-cache
Please guide me. What am i doing wrong?? HELP!!
As Peter had written in his comment, the cause of the problem is inability of Spring to load Jackson. It is not loaded by dependencies by default. After I've added the dependency
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.2</version>
</dependency>
the JSON was returned after typing the address in the browser, without any tricks with Accept headers (as it is supposed to do).
Tested on Tomcat 7.0.
You have incorrect response content type it supposed to be application/json.
You need to add jackson to your /lib directory.
and you should have
<mvc:annotation-driven />
In your serlvet-name.xml file.
In addition I recommend you to map your request as get and try to browse it with Google Chrome,to see if it returns correct result. It has very good json representation.
The problem is not on server side, but on the client one.
Take a look at the error message carefully: The requested resource (generated by server side) is only capable of generating content (JSON) not acceptable (by the client!) according to the Accept headers sent in the request.
Examine your request headers:
Accept */*
Try this way:
function getCities() {
jq(function() {
jq.post(
"getCities.html", // URL to post to
{ stateSelect: jq("#stateSelect").val() }, // Your data
function(data) { // Success callback
jq("#cities").replaceWith('<span id="cities">Testing</span>');
},
"json" // Data type you are expecting from server
);
});
}
This will change your Accept header to the following (as of jQuery 1.5):
Accept: application/json, text/javascript, */*; q=0.01
This will explicitly tell the server side that you are expecting JSON.
Using jQuery , you can set contentType to desired one (application/json; charset=UTF-8' here) and set same header at server side.
REMEMBER TO CLEAR CACHE WHILE TESTING.
I too had a similar problem while using the Apache HTTPClient to call few services. The problem is the client and not the server. I used a HTTPRequester with header accepting application/json and it worked fine.

jQuery $.ajax(), $.post sending "OPTIONS" as REQUEST_METHOD in Firefox

Having trouble with what I thought was a relatively simple jQuery plugin...
The plugin should fetch data from a php script via ajax to add options to a <select>. The ajax request is pretty generic:
$.ajax({
url: o.url,
type: 'post',
contentType: "application/x-www-form-urlencoded",
data: '{"method":"getStates", "program":"EXPLORE"}',
success: function (data, status) {
console.log("Success!!");
console.log(data);
console.log(status);
},
error: function (xhr, desc, err) {
console.log(xhr);
console.log("Desc: " + desc + "\nErr:" + err);
}
});
This seems to work fine in Safari. In Firefox 3.5, the REQUEST_TYPE on the server is always 'OPTIONS', and the $_POST data does not appear. Apache logs the request as type 'OPTIONS':
::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46
Why would this ajax call work in Safari, but not Firefox, and how do I fix it for Firefox?
Response Headers
Date: Wed, 08 Jul 2009 21:22:17 GMT
Server:Apache/2.0.59 (Unix) PHP/5.2.6 DAV/2
X-Powered-By: PHP/5.2.6
Content-Length 46
Keep-Alive timeout=15, max=100
Connection Keep-Alive
Content-Type text/html
Request Headers
Host orderform:8888
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
Connection keep-alive
Origin http://ux.inetu.act.org
Access-Control-Request-Method POST
Access-Control-Request-Headers x-requested-with
Here is a picture of the Firebug output:
The reason for the error is the same origin policy. It only allows you to do XMLHTTPRequests to your own domain. See if you can use a JSONP callback instead:
$.getJSON( 'http://<url>/api.php?callback=?', function ( data ) { alert ( data ); } );
I used the following code on Django side to interpret the OPTIONS request and to set the required Access-Control headers. After this my cross domain requests from Firefox started working. As said before, the browser first sends the OPTIONS request and then immediately after that the POST/GET
def send_data(request):
if request.method == "OPTIONS":
response = HttpResponse()
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
response['Access-Control-Max-Age'] = 1000
# note that '*' is not valid for Access-Control-Allow-Headers
response['Access-Control-Allow-Headers'] = 'origin, x-csrftoken, content-type, accept'
return response
if request.method == "POST":
# ...
Edit: it seems to be that at least in some cases you also need to add the same Access-Control headers to the actual response. This can be a little bit confusing, since the request seems to succeed, but Firefox does not pass the contents of the response to the Javascript.
This mozilla developer center article describes various cross-domain request scenarios. The article seems to indicate that a POST request with content type of 'application/x-www-form-urlencoded' should be sent as a 'simple request' (with no 'preflight' OPTIONS request). I found , however, that Firefox sent the OPTIONS request, even though my POST was sent with that content type.
I was able to make this work by creating an options request handler on the server, that set the 'Access-Control-Allow-Origin' response header to '*'. You can be more restrictive by setting it to something specific, like 'http://someurl.com'. Also, I have read that, supposedly, you can specify a comma-separated list of multiple origins, but I couldn't get this to work.
Once Firefox receives the response to the OPTIONS request with an acceptable 'Access-Control-Allow-Origin' value, it sends the POST request.
I've fixed this issue using an entirely-Apache based solution. In my vhost / htaccess I put the following block:
# enable cross domain access control
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"
# force apache to return 200 without executing my scripts
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]
You may not need the latter part, depending on what happens when Apache executes your target script. Credit goes to the friendly ServerFault folk for the latter part.
This PHP at the top of the responding script seems to work. (With Firefox 3.6.11. I have not yet done a lot of testing.)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
if(array_key_exists('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', $_SERVER)) {
header('Access-Control-Allow-Headers: '
. $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
} else {
header('Access-Control-Allow-Headers: *');
}
if("OPTIONS" == $_SERVER['REQUEST_METHOD']) {
exit(0);
}
I had same problem with sending requests to google maps, and solution is quite simple with jQuery 1.5 - for dataType use dataType: "jsonp"
Culprit is preflight request using OPTIONS method
For HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method.
Web specification refer to: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
I resolved the problem by adding following lines in Nginx conf.
location / {
if ($request_method = OPTIONS ) {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 200;
}
location ~ ^/(xxxx)$ {
if ($request_method = OPTIONS) {
rewrite ^(.*)$ / last;
}
}
I was looking through source 1.3.2, when using JSONP, the request is made by building a SCRIPT element dynamically, which gets past the browsers Same-domain policy. Naturally, you can't make a POST request using a SCRIPT element, the browser would fetch the result using GET.
As you are requesting a JSONP call, the SCRIPT element is not generated, because it only does this when the Type of AJAX call is set to GET.
http://dev.jquery.com/ticket/4690
We had a problem like this with ASP.Net. Our IIS was returning an Internal Server Error when trying to execute a jQuery $.post to get some html content due to PageHandlerFactory was restricted to respond only GET,HEAD,POST,DEBUG Verbs. So you can change that restriction adding the verb "OPTIONS" to the list or selecting "All Verbs"
You can modify that in your IIS Manager, selecting your website, then selecting Handler Mappings, double click in your PageHandlerFactory for *.apx files as you need (We use Integrated application pool with framework 4.0). Click on Request Restrictions, then go to Verbs Tabn and apply your modification.
Now our $.post request is working as expected :)
Check if your form's action URL includes the www part of the domain, while the original page you have opened is viewed without www.
Typically done for Canonical Urls..
I struggled for hours before stumbling upon this article and found the hint of Cross Domain.
I seems that if o.url = 'index.php' and this file exists is ok and returning a success message in the console. It returns an error if I use url:http://www.google.com
If doing a post request why not using directly the $.post method:
$.post("test.php", { func: "getNameAndTime" },
function(data){
alert(data.name); // John
console.log(data.time); // 2pm
}, "json");
It is so much simpler.
I have posted a clear example of how to solve this if control the server code of the domain you are POSTing to. This answer is touched on in this thread, but this more clearly explains it IMO.
How do I send a cross-domain POST request via JavaScript?
Solution to this is:
use dataType: json
add &callback=? to your url
this worked on calling Facebook API and with Firefox. Firebug is using GET instead of OPTIONS with the above conditions (both of them).
Another possibility to circumvent the problem is to use a proxy script. That method is described for example here
Can you try this without
contentType:application/x-www-form-urlencoded
Try adding the option:
dataType: "json"
function test_success(page,name,id,divname,str)
{
var dropdownIndex = document.getElementById(name).selectedIndex;
var dropdownValue = document.getElementById(name)[dropdownIndex].value;
var params='&'+id+'='+dropdownValue+'&'+str;
//makerequest_sp(url, params, divid1);
$.ajax({
url: page,
type: "post",
data: params,
// callback handler that will be called on success
success: function(response, textStatus, jqXHR){
// log a message to the console
document.getElementById(divname).innerHTML = response;
var retname = 'n_district';
var dropdownIndex = document.getElementById(retname).selectedIndex;
var dropdownValue = document.getElementById(retname)[dropdownIndex].value;
if(dropdownValue >0)
{
//alert(dropdownValue);
document.getElementById('inputname').value = dropdownValue;
}
else
{
document.getElementById('inputname').value = "00";
}
return;
url2=page2;
var params2 = parrams2+'&';
makerequest_sp(url2, params2, divid2);
}
});
}
I had a similar problem with trying to use the Facebook API.
The only contentType which didn't send the Preflighted request seemed to be just text/plain... not the rest of the parameters mentioned at mozilla here
Why is this the only browser which does this?
Why doesn't Facebook know and accept the preflight request?
FYI: The aforementioned Moz doc suggests X-Lori headers should trigger a Preflighted request ... it doesn't.
You need to do some work on server side. I see you are using PHP on server side, but solution for .NET web application is here:
Cannot set content-type to 'application/json' in jQuery.ajax
Do the same in PHP script and it will work. Simply: At first request browser is asking server if is allowed to send such data with such type and second request is the proper/allowed.
Try to add the following:
dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),
I used a proxy url to solve a similar problem when I want to post data to my apache solr hosted in another server. (This may not be the perfect answer but it solves my problem.)
Follow this URL: Using Mode-Rewrite for proxying, I add this line to my httpd.conf:
RewriteRule ^solr/(.*)$ http://ip:8983/solr$1 [P]
Therefore, I can just post data to /solr instead of posting data to http://ip:8983/solr/*. Then it will be posting data in the same origin.
I already have this code handling well my cors situation in php:
header( 'Access-Control-Allow-Origin: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Headers: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Credentials: true' );
And it was working fine locally and remotely, but not for uploads when remote.
Something happen with apache/php OR my code, I didn't bother to search it, when you request OPTIONS it returns my header with cors rules but with 302 result. Therefore my browser doesn't recognise as an acceptable situation.
What I did, based on #Mark McDonald answer, is just put this code after my header:
if( $_SERVER['REQUEST_METHOD'] === 'OPTIONS' )
{
header("HTTP/1.1 202 Accepted");
exit;
}
Now, when requesting OPTIONS it will just send the header and 202 result.
Please be advised:
JSONP supports only the GET request method.
*Send request by firefox:*
$.ajax({
type: 'POST',//<<===
contentType: 'application/json',
url: url,
dataType: "json"//<<=============
...
});
Above request send by OPTIONS(while ==>type: 'POST')!!!!
$.ajax({
type: 'POST',//<<===
contentType: 'application/json',
url: url,
dataType: "jsonp"//<<==============
...
});
But above request send by GET(while ==>type: 'POST')!!!!
When you are in "cross-domain communication" , pay attention and be careful.

Resources