Why jQuery.parseJSON does not parse this valid JSON document in Firefox? - javascript

Server returns this JSON document:
{
"username-found": true,
"question-required": true
}
Which successfully passes JSONLint's validity check.
In web browser:
$.post('my_url', {"post":"data"}, function(data) {
data = $.parseJSON(data);
});
The code runs and successfully parses the JSON document in Opera 12 browser, however in Firefox 16, JavaScript error occurs and says "not well-formed".
JQuery is of version 1.7.2.
I cannot see what I did wrong there, do you know?
Edit:
Does it have anything to do with the way server returns the JSON? Here it is:
return new StreamingResolution("text", new StringReader(json.toString()));
uggestion, I might have found the cause. When I did alert(data), Firefox tells me that data is an object, Opera tells me that data is the JSON string.

Solution 1 (Client) - Set DataType in jQuery Request
I think the internals are a bit different in that specific browser version (because jQuery tries to detect the dataType automatically and is doing the parsing internally in the case of a JSON response) and JSON is automatically encoded in FF and not in Opera?
Try to add the dataType so jQuery will handle this (I would prefer that):
$.post('my_url', {"post":"data"}, function(data) {
// data should be an json object here
}, 'json');
It's just a guess.
OR Solution 2 (Server) - Send MIME type
You could also send a correct MIME type from the server so you don't have to set the dataType on the client. Its up to you but I think that would be the correct solution.
Regarding this answer it should be application/json.
Reference
How is the dataType detected automatically in jQuery?
Default: Intelligent Guess (xml, json, script, or html) 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).
Source: http://api.jquery.com/jQuery.ajax/

You can directly use the data object directly ..
No need to use $.parseJSON();

You also have a $.getJSON shortcut method in jQuery. Maybe jQuery automatically uses the best configuration for this case and maybe start working
Here is the $.getJSON documentation

Related

JSON won`t get parsed with variables out of an array

I don´t understand why my JSON doesn´t get parsed. I hope someone could explain this to me. I try to send a JSON from PHP to JavaScript.
This code works fine:
From PHP
echo json_encode(array($row['jobunique'], $row['jobtitle']));
to JavaScript
success: function(getjoblist) {
var getjobdetails = $.parseJSON(getjoblist);
}
But this code gives me an error back:
From PHP - data comes out of an array
echo json_encode(array($data[2], $data[3]));
I thought, maybe it's an object and I need to make a string out of the variables like this:
echo json_encode(array(strval($data[2]), strval($data[3])));
But it did not work either.
Here is the JavaScript code:
success: function(callback) {
var namearray = $.parseJSON(callback);
}
Here is the error from the console:
Uncaught SyntaxError: Unexpected token in JSON at position 0
Here is the network-tab:
The callback variable is already an array. JQuery's AJAX methods automatically parse responses, if there are JSON specific headers present (Content-type: application/json).
Try run JSON.parse(["Fabi","Squ"]) in the console, it will get you the same error message.
Read more about this at http://api.jquery.com/jquery.ajax/ :
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).

How does Javascript differentiate between Json Objects and String?

I was reading a code snippet and figuring out how it works when this weird javascript problem came up.
In their javascript they called
var apiUrl = '/api/v1/pin/?format=json&order_by=-id&offset='+String(offset);
...
$.get(apiUrl, function(pins) {
for (...; i < pins.objects.length; i++) ... // works fine
});
their api returns this json format:
{"meta": {"limit": 50, "next": "?limit=50&format=json&order_by=-id&offset=60", "offset":
10, "previous": null, "total_count": 79}, "objects": [ {...},{...}, ... ]}
I tried to mimic it but the $.get never accepted my simplified json string.
// my attempt
$.get(myApiUrl, function(pins) {
for (...; i < pins.objects.length; i++) ... // ERROR: undefined length
});
My Json string is in the similar but shortened format.
{"objects": [{...},{...}, ... ]}
I couldn't get it to work until I googled the $.getJson() command. I am just wondering why their javascript code works with just $.get whereas mine has to use $.getJson??
Is it some kind of header you can set to force javascript to read it as json?
If you don't specify content type explicitly jQuery will try to determine data type based on headers returned by server.
If you are not using JSON serializers, then verify validity of your JSON using http://jsonlint.com/ or this, otherwise you will get an error.
Correct ContentType header for JSON is: application/json
In both cases the AJAX call returns a string. jQuery somehow has to figure out what to do with it. How it does that depends on the dataType option.
The docs call the default value Intelligent guess. So how to guess? Evaluating the Content-Type header of the response. If it's application/jsonthen jQuerywill try to create an object.
To ensure that jQuerywill always try to interpret the response as JSON you can set the dataType to json.
Set the HTTP response header Content-Type to application/json
Eg:
HTTP/1.1 200 OK
Content-Type: application/json

Handling dynamic HTTP Content-Type with jquery Ajax

I have a perl script URL which gives me a ZIP file, it processes the data and dynamically set the Content-Type to 'application/zip' in the http-header.
Perl code looks like this:
WPHTTPResponse::setHeader( 'Content-disposition', 'attachment;filename="test.zip"');
WPHTTPResponse::setHeader( 'Content-type', 'application/zip');
print $result;
In frontend, I am using this script direct in HREF:
Download
But I have a requirement of showing an alert message if $result is NULL in perl script.
What I am thinking is: I will send the file with Content-Type=>application/zip if the $result if not null, otherwise I will send the JSON response with error message that there is no file to download.
For this I would need to dynamically check the content type using JS:
$.ajax({
url: '/script',
data: {....},
success: function(response) {
if(response.contentType == 'application/zip'){
//download using javascript
}
else{
$.parseJSON(response);
alert(response.msg);
}
}
});
I'd appreciate any help.
Although your method should work, this is a case where using using HTTP error codes would probably be a good choice.
Depending on why $result is null one of these should be appropriate.
400 Bad Request
406 Not Acceptable
410 Gone
This would make your code slightly more 'obvious' as you would be using the HTTP status for exactly what it was meant for, rather than re-implementing the exact same thing in a proprietary way in your code. IMHO it would also make your code a bit easier to maintain as it would separate the success from the error.
You can still include JSON as part of the error response, to be able display information about exactly why the request didn't result in any data being returned to the client.
btw I'd avoid using 404 as the error code, even though it is technically the most 'appropriate' code just because it would cause confusion if a real 404 error occurred.
Use HEAD-request for check content size before download.
Client-side:
Attach click-event handler to <a>-element.
On click-event send HEAD-request throw XHR.
On XHR-response check content size.
If size is zero, then show alert and prevent default event handler.
If size is not zero, nothing to do.
Server-side:
Compute content size on HEAD-request.

Sending a JSON POST request with BSF Preprocessor

I am working with JMeter to write some performance tests. One of the things that I need to do is to construct a huge json request dynamically and send it as POST request paylod. Using BSF preprocessor, I am able to modify the payload dynamically however my javascript string is being encoded, while I want to send it without being encoded.
I am not sure how BSF preprocessor can stop it from being encoded. The command I currently use to change my POST request payload is as follows:
var jsonData = '[{"item":"value","something":"everything"}]';
sampler.addArgument("",jsonData);
I would really appreciate if you can point me to some examples which clearly explain how bsf preprocessors are expected to be used.
Any pointers to skip the encoding will also be appreciated.
Since JMeter 2.6 you can use the RAW request pane using Post Body tab.
So your solution is to do the following:
In BSF Sampler, put you JSON in a variable:
var jsonData = '[{"item":"value","something":"everything"}]';
vars.putObject("jsonData",jsonData);
In Post Body, put:
${jsonData}
Another option using your method is to put in BSFPreProcessor using Beanshell language (not javascript):
import org.apache.jmeter.protocol.http.util.HTTPArgument;
String jsonData = "[{\"item\":\"value\",\"something\":\"everything\"}]";
HTTPArgument arg =new HTTPArgument("", jsonData, null, true);
arg.setAlwaysEncoded(false);
sampler.getArguments().addArgument(arg);
Regards
Philippe M.
set property on your sampler "HTTPArgument.always_encode" to false this should disable argument encoding

Ext.Ajax.request callbacks never called when isUpload is true

I'm using ExtJS to make a form that generates a report from the data in the database in CSV format. After the user chooses a simple range of dates to extract the data and submits, running the following code :
var frm = document.createElement('form');
frm.id = 'frmDummy';
frm.name = id;
document.body.appendChild(frm);
Ext.MessageBox.wait('Generating CSV File ...');
Ext.Ajax.request({
url: 'csv_extract_ajax.php?start_time='+txtDateFieldFrom.getRawValue()+'&end_time='+txtDateFieldTo.getRawValue(),
method : 'POST',
form: Ext.fly('frmDummy'),
isUpload: true,
success: function(o, r, n){
Ext.MessageBox.updateProgress(1);
Ext.MessageBox.hide();
},
failure: function(o, r, n){
Ext.MessageBox.updateProgress(1);
Ext.MessageBox.hide();
},
callback: function(o, r, n){
Ext.MessageBox.updateProgress(1);
Ext.MessageBox.hide();
},
scope: this
});
The associated php file simple outputs a CSV string, working file.
Since the isUpload is true, it seems that the callback is never returned to the user. As soon as I remove it, the callback is called but the file is not uploaded to the client.
The problem now, everything is working perfectly but the MessageBox never disappears since the callbacks are never called (success, failure or callback)
Any idea ? :P
Additional info:
PHP header :
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: private");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=$filename");
header("Accept-Ranges: bytes");
This is an excerpt from Ext.Ajax.request documentation:
isUpload : Boolean (Optional) True if
the form object is a file upload (will
usually be automatically detected).
File uploads are not performed using
normal "Ajax" techniques, that is they
are not performed using
XMLHttpRequests. Instead the form is
submitted in the standard manner with
the DOM element temporarily
modified to have its target set to
refer to a dynamically generated,
hidden which is inserted into
the document but removed after the
return data has been gathered. The
server response is parsed by the
browser to create the document for the
IFRAME. If the server is using JSON to
send the return object, then the
Content-Type header must be set to
"text/html" in order to tell the
browser to insert the text unchanged
into the document body. The response
text is retrieved from the document,
and a fake XMLHttpRequest object is
created containing a responseText
property in order to conform to the
requirements of event handlers and
callbacks. Be aware that file upload
packets are sent with the content type
multipart/form and some server
technologies (notably Java EE) may require
some custom processing in order to
retrieve parameter names and parameter
values from the packet content.
As you can see, upload request is returned via IFRAME and only emulates standard AJAX response, so that callbacks are not called.
Try changing:
l: 'csv_extract_ajax.php?start_time='+txtDateFieldFrom.getRawValue()+'&end_time='+txtDateFieldTo.getRawValue(),
to
l: 'csv_extract_ajax.php?'+ Ext.urlEncode({ start_time: txtDateFieldFrom.getRawValue(), end_time: txtDateFieldTo.getRawValue() }),
Is there any error displayed in the page?
What is the content type of response?
The extjs api doc says it should be set to "text/html".
If it still not working you can try to put a breakpoint in doFormUpload(). This method is present in connection.js. Inside this you can find a inner method called cb(), this method will be called once the server returns. You can start debugging from there.
all the best.
As soon as I remove it, the callback
is called but the file is not uploaded
to the client.
Setting isUpload to true means you are gonna to upload file from client to server, but this is not your case, I'm afraid.
Do you noticed this in every browser, or just in a particular browser?
Firefox 3.5 (with Firebug installed) appears to have a bug that means that readystatechange does not get updated which would mean that callbacks do not get invoked.
If you don't have a file to upload, why are you setting isUpload to true?
Also, if you are posting a data to a PHP script and if that script returns a CSV string, why are you trying to send it as attachment? Why not send it as regular response text?

Categories

Resources