jQuery ignores HTTP request method and appends weird URL parameters - javascript

I have a web service that expects POST requests carrying a JSON string in the body. I'm trying to use this web service using jQuery, but I have two problems :
1) jQuery seems to always use the GET method, no matter what I do ;
2) jQuery seems to append weird things into the URL.
The relevant pice of my code :
var WEB_SERVICE_URL = 'http://localhost/XXXX/';
// ...
$.post({
url: WEB_SERVICE_URL + 'GetConfigLabels/',
contentType: 'application/json; charset=utf-8',
dataType: 'jsonp',
data: JSON.stringify(data),
processData: false,
success: function(response) {
// Whatever
},
error: function(xhr, message) {
// Whatever
}
});
The developper tools of the browser (Firefox Quantum 60.0.2) shows me a weird URL :
http://localhost/XXXX/GetConfigLabels/?callback=jQuery331012146934861340841_1530707758905&{}&_=1530707758906
While the following was expected :
http://localhost/XXXX/GetConfigLabels/
Also the HTML file is openned as a file (using file:///) through the file system, hence the use of JSONP for cross domain.
I failed to find existing questions related to this issue. What could be causing this ? Thank you !

Please refer to the dataType : json section at http://api.jquery.com/jquery.ajax/ :
"json": Evaluates the response as JSON and returns a JavaScript
object. Cross-domain "json" requests that have a callback placeholder,
e.g. ?callback=?, are performed using JSONP unless the request
includes jsonp: false in its request options. The JSON data is parsed
in a strict manner; any malformed JSON is rejected and a parse error
is thrown. As of jQuery 1.9, an empty response is also rejected; the
server should return a response of null or {} instead. (See json.org
for more information on proper JSON format
overrding random name of callback using jsonpCallback :
jsonpCallback Type: String or Function() Specify the callback function
name for a JSONP request. This value will be used instead of the
random name automatically generated by jQuery. It is preferable to let
jQuery generate a unique name as it'll make it easier to manage the
requests and provide callbacks and error handling. You may want to
specify the callback when you want to enable better browser caching of
GET requests. As of jQuery 1.5, you can also use a function for this
setting, in which case the value of jsonpCallback is set to the return
value of that function.

Related

Ajax MVC Partial Returning Correct Response Yet Fires the Error Handler

This has me completely stumped. So odd.
I have this Ajax function defined:
$.ajax({
type: 'GET',
dataType: 'text/HTML',
url: getLicenseeDetailsUrl,
success: function (response) {
$('#licenseeDetails').html('');
$('#licenseeDetails').html(response);
},
error: function (xhr) {
alert('Failed to get licensee details');
}
});
And I have it calling into my controller which has an action like:
public ActionResult LoadLicenseeDetails(long licenseeId)
{
var model = new LicenseeDetailsViewModel();
var licencesee = _licensingRepository.LoadById(licenseeId);
var licenses = _licensingRepository.LoadLicenses(licenseeId);
model.Licencee = Mapper.Map<Licensee, LicenceeViewModel>(licencesee);
model.Licences = Mapper.Map<IEnumerable<License>, IEnumerable<LicenceViewModel>>(licenses);
return this.PartialView("_LicenseeDetails", model);
}
This all seems to be working as expected without any errors, however it ends up firing the Ajax error function, not the success function.
Looking at the xhr.responseText I can see the correct response information from the action controller!!
All with a status 200 OK as well. What on earth am I doing wrong here?
What on earth am I doing wrong here?
this:
dataType: 'text/HTML'
should become:
dataType: 'html'
Quote from the documentation of the dataType parameter:
dataType (default: Intelligent Guess (xml, json, script, or html))
Type: String
The type of data that you're expecting back from the
server. If none is specified, jQuery will try to infer it based on the
MIME type of the response (an XML MIME type will yield XML, in 1.4
JSON will yield a JavaScript object, in 1.4 script will execute the
script, and anything else will be returned as a string). The available
types (and the result passed as the first argument to your success
callback) are:
"xml": Returns a XML document that can be processed via jQuery.
"html": Returns HTML as plain text; included script tags are
evaluated when inserted in the DOM.
"script": Evaluates the response as JavaScript and returns it as plain text. Disables caching by
appending a query string parameter, "_=[TIMESTAMP]", to the URL unless
the cache option is set to true. Note: This will turn POSTs into GETs
for remote-domain requests.
"json": Evaluates the response as JSON and returns a JavaScript object. The JSON data is parsed in a strict manner; any malformed JSON is rejected and a parse error is thrown. As of jQuery 1.9, an empty response is also rejected; the server should
return a response of null or {} instead. (See json.org for more information on proper JSON formatting.)
"jsonp": Loads in a JSON block using JSONP. Adds an extra "?callback=?" to the end of your URL to specify the callback. Disables caching by appending a query string parameter, "_=[TIMESTAMP]", to the URL unless the cache option is set to true.
"text": A plain text string.
multiple, space-separated values: As of jQuery 1.5, jQuery can convert a dataType from what it received in the Content-Type header to what you require. For example, if you want a text response to be treated as XML, use "text xml" for the dataType. You can also make a JSONP request, have it received as text, and interpreted by jQuery as XML: "jsonp text xml." Similarly, a shorthand string such as "jsonp xml" will first attempt to convert from jsonp to xml, and, failing that, convert from jsonp to text, and then from text to xml.
Or even better, simply get rid of this parameter. jQuery is intelligent enough to use the Content-Type response HTTP header set by the server in order to deduce the correct type and process the parameter passed to the success callback.
Look at the Console tab of your javascript debugging toolbar in the browser. It will provide you with more information about the error.

Get JSONPto work

I am trying to access data from a php server with a cross domain support. So when i try $.ajax with dataType : 'jsonp' i have an error in console: Uncaught SyntaxError: Unexpected token The file is interpret as a javascript file an the request fail. Have you an idea for get data whithout this error.
$.ajax({
url : 'http://domaine.com/json.php',
contentType: "application/json; charset=utf-8",
dataType : 'jsonp',
success : function(data){
console.log(data);
// no enter in this callback
},
complete: function(data1, data2, data3){
// no data from file.js
}
});
First make sure that your PHP script supports JSONP. Identify the query string parameter that needs to be passed so that the script returns JSONP. Then test it in your browser by directly entering the following address in your address bar:
http://domain.com/json.php?callback=abc
You should see something along the lines of:
abc({ ... some JSON here ... })
You might need to adjust the callback name parameter if your PHP script expects a different one. This could be the case if you see the following output ({ ... some JSON here ... } without being wrapped in your javascript function)
And once you have ensured that you have a valid PHP script that returns JSONP you could consume it:
$.ajax({
url : 'http://domain.com/json.php',
jsonp: 'callback',
dataType : 'jsonp',
success : function(data){
console.log(data);
// no enter in this callback
},
complete: function(data1, data2, data3){
// no data from file.js
}
});
Things to notice:
I have specified the callback using the jsonp: 'callback' parameter
I have gotten rid of the contentType: 'application/json' parameter because jQuery's implementation of JSONP uses script tags which doesn't allow you to set any request headers.
You need to add ?callback=? to the request so that the proper callback is evaluated. It may not be called callback, though. You need to find out what it is called from the domain.
If the domain (and browser) supports CORS, you don't even need to use JSONP. You can use a normal request.

Javascript automatically parsing nested object

This is more a question of procedure than anything else. I'm curious why this happens and I can't seem to find any documentation on this "feature" within the ECMA script documentation.
When I make an AJAX call within jQuery to my server, it returns the following JSON response to the page:
{"version":"v1","status":"OK","timestamp":"2013-02-14 10:32:45","data":"true","error":""}
With this string I have to call jQuery.parseJSON(string); to get it as an object, and the be able to reference it as an object.
However, when my server returns something like this:
{"version":"v1","status":"OK","timestamp":"2013-02-14 10:12:19","data":{"a":"asgsadfga","b":false,"c":[]},"error":""}
Javascript automatically loads this an an object without the need to parse. It would seem that because this example returns a nested object, despite the fact it was returned from the server as a string, Javascript will immediately recognize that, and parse the string for me.
Is this expected functionality, and if so, can anyone point me to the documentation of this?
EDITED:
Here is the offending AJAX call:
jQuery.ajax({
url: url,
type: 'GET',
async: false,
success: function (result) {
console.log(result)
}
Make sure that your server sets the proper Content-Type response HTTP header:
Content-Type: application/json
So that jQuery will automatically parse the JSON string returned by your server to a javascript object which will be passed as argument to your success callback.
Or if for some reason you've got some broken server side script which you have no control over you could set the dataType parameter to force jQuery to parse the result as JSON:
$.ajax({
url: '/script.cgi',
type: 'POST'
dataType: 'json',
success: function(result) {
// result will be a javascript object
}
});
But obviously the proper thing to do is to fix your server side script to return the proper Content-Type response header.
According to ajax() in jQuery API Documentation under dataType:
dataType (default: Intelligent Guess (xml, json, script, or
html))Type: String The type of data that you're expecting back from
the server. If none is specified, jQuery will try to infer it based
on the MIME type of the response (an XML MIME type will yield XML, in
1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string).
Hope this helps.
You should specify dataType to be json in your $.ajax call. dataType is the MIME you are expecting to receive from the server. contentType is what the server is expecting from you.

How to use JSONP

I have the following code
function exista(word) {
alert(word);
var exists = 1;
jQuery.ajax({
async: false,
url: "http://api.wordreference.com/0.8/key/json/roen/" + word,
dataType: 'json',
method: "GET",
success: function(transport) {
if (transport.Error || transport.Response)
exists = 0;
}
});
return exists;
}
which verifies if a word exists or not in a dictionary. Problem is it gives an Access-Control-Allow-Origin error. From what I gathered it seems I must use JSONP but I can't really figure out how (sorry, I am just beginning to learn JavaScript and all that). So, got any idea on how to modify the above code?
Thank you.
Your dataType should be jsonp, not 'json`.
UPDATE
According to http://www.wordreference.com/docs/api.aspx:
Additionally, for JSPONp, the JSON API can take an optional callback
function in the query string; simply add "?callback={yourCallback}" to
the end of the URL.
so the API does support JSONP.
Additionally, JSONP means "JSON with padding", so you will get a JSON response. JSONP merely allows use of CORS.
By changing your dataType to jsonp:
"jsonp": Loads in a JSON block using JSONP. Adds an extra
"?callback=?" to the end of your URL to specify the callback. Disables
caching by appending a query string parameter, "_=[TIMESTAMP]", to the
URL unless the cache option is set to true.
You can override the default callback by specifying one with the jsonpCallback setting.
Finally, you should also add an error handler and set async to true:
jQuery.ajax({
"async": true, //cannot be false for JSONP
"url": "http://api.wordreference.com/0.8/key/json/roen/" + word,
"dataType": 'jsonp',
"method": "GET",
"error": function (jqXHR, textStatus, errorThrown) {
//included so you can see any errors
console.log(textStatus + ': ' + errorThrown);
},
"success": function (data, textStatus, jqXHR) {
//According to API documentation
//data will not likely contain either Error, or Response
//so, exists will likely not change to 0
if (data.Error || data.Response) {
exists = 0;
}
}
});
UPDATE:
The solution to both the error and the "need to be synchronous" is going to be what Pointy pointed out earlier. You'll have to create a server-side proxy that runs on the same domain as your script.
The server-side proxy can return JSONP, but frankly simply returning JSON or XML is simpler since CORS is not an issue, and the proxy can be synchronous. For a PHP example script, the Yahoo! Developer Network hosts source code for a simple proxy.
For anything else regarding a server-side web service proxy, you'd need to specify which server language you're using (and it would probably be better suited as a different question).
For JSONP to work, you not only have to code for it on your side, but the site you're targeting has to expect to be used that way as well, and respond to requests accordingly.
If the other site does not have a JSONP API already, and you have no control over it, then JSONP is not an answer. You'll have to create a server-side proxy of your own.
edit — according to the site, they do support JSONP. You just need to add "?callback=?" to the end of the URL.

jQuery + JSONP + Yahoo Query Language

I want to get live currency rates from an external source, so I found this great webservice:
Currency Convertor
This service is working like a charm, the only downside is that it does not provide JSONP results, only XML. Therefore we have a cross browser problem while trying to consume this webservice using jQuery $.ajax().
So I found Yahoo Query Language which returns results as JSONP and also mangae to consume other webservices and return me the results. This is also working, here is an example URL:
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'http%3A%2F%2Fwww.webservicex.net%2FCurrencyConvertor.asmx%2FConversionRate%3FFromCurrency%3DNOK%26ToCurrency%3DEUR'&format=json&diagnostics=true&callback=cbfunc
This URL return JSONP result and is working like a charm, but the problem appears when I use this in my code:
$.ajax({
type: "GET",
url: urlToWebservice,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
$("#status").html("OK: " + data.text);
},
error: function(xhr, textStatus, errorThrown) {
$("#status").html("Unavailable: " + textStatus);
}
});
When I try to run this code nothing happens, and I can see this error message in my Firebug javascript debugger:
cbfunc is not defined
cbfunc is the name of the container which surrounds the JSON response, but why does it say not defined?
EDIT:
This is my new code, but I still get the cbfunc is not defined
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'http%3A%2F%2Fwww.webservicex.net%2FCurrencyConvertor.asmx%2FConversionRate%3FFromCurrency%3DNOK%26ToCurrency%3DEUR'&format=json&callback=cbfunc",
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'cbfunc'
});
function cbfunc(data) {
alert("OK");
}
And the "OK" message is never fired...
If available, use the jsonpCallback parameter in the call to $.ajax like:
jsonpCallback: "cbfunc",
Its description, from the jQuery API docs reads:
Specify the callback function name for a jsonp request. This value will be used instead of the random name automatically generated by jQuery.
The docs later go on to say:
It is preferable to let jQuery generate a unique name as it'll make it easier to manage the requests and provide callbacks and error handling. You may want to specify the callback when you want to enable better browser caching of GET requests.
However it is not advised to make use of this "preferable" behaviour when making use of YQL. Precisely why that approach is not ideal might make this answer far too verbose, so here is a link (from the YQL blog) detailing the problems with jQuery's preferred approach, making use of jsonpCallback and so on: Avoiding rate limits and getting banned in YQL and Pipes: Caching is your friend
You should let jQuery handle the callback by changing urlToWebservice to end in callback=?
The reason it's not working is because by specifying callback=cbfunc in the querystring generates a URL of the type:
http://query.yahooapis.com/...&callback=cbfunc&callback=jsonp1277417828303
Stripped out all uninteresting parts, but the URL contains two callback parameters. One of them is managed by jQuery, and the other one not. YQL only looks at the first callback parameter and returns a response wrapped around that.
cbfunc({"query":{...}});
However, there is no function named cbfunc in your script, so that's why you are getting the undefined error. jQuery created an implicit function named jsonp1277417828303 in the above example, and the response from YQL should instead have been:
jsonp1277417828303({"query":{...}});
for jQuery to act upon it, and return the response to your success callback which it never got to do.
So, as #SLaks suggested, remove the &callback=cbfuncfrom your URL, or replace it with &callback=? to let jQuery handle things.
See a working example.
You definitely should give jQuery-JSONP a try: http://code.google.com/p/jquery-jsonp/
Simplifies everything :)

Categories