String cannot be converted into JSON in Javascript - javascript

self.str = "
{"queryString":"user=test&password=1 OR TRUE ; -- ' OR TRUE; -- OR TRUE; K2FUZZ " OR TRUE; -- OR TRUE; K2FUZZ '","clientIP":"127.0.0.1","clientPort":"43470","dataTruncated":false,"contentType":"","requestURI":"/DemoApplication-0.0.1-SNAPSHOT/UserCheck3","generationTime":0,"body":"","method":"GET","url":"/DemoApplication-0.0.1-SNAPSHOT/UserCheck3?user=test&password=test123"}
"
self.obj = JSON.parse(self.str);
I am getting error:
base.js:1 SyntaxError: Unexpected token O in JSON at position 82
at JSON.parse ()
I tried various methods but nothing works. Can anyone tell me why this error is occurring and how can I fix it?
Just for the context, self.str contains a string value that I have obtained from an API response.

If you work on this backwards - by creating an object and stringifying it - you can see that the quotes in queryString need to be escaped. You can then turn it into valid JSON.
So, whatever data this JSON is coming from needs to be properly formatted because it's not valid JSON at the moment.
const obj = {
"queryString": "user=test&password=1 OR TRUE ; -- \' OR TRUE; -- OR TRUE; K2FUZZ \"OR TRUE;--OR TRUE;K2FUZZ\'",
"clientIP": "127.0.0.1",
"clientPort": "43470",
"dataTruncated": false,
"contentType": "",
"requestURI": "/DemoApplication-0.0.1-SNAPSHOT/UserCheck3",
"generationTime": 0,
"body": "",
"method": "GET",
"url": "/DemoApplication-0.0.1-SNAPSHOT/UserCheck3?user=test&password=test123"
}
const str = JSON.stringify(obj);
document.querySelector('pre').textContent = JSON.stringify(obj, null, 2);
// console.log(JSON.parse(str));
<pre></pre>

Related

url encoding php data into json object

Please read - this isn't just simply doing json_encode from php to javascript.
Our billing system uses Authorize.net. Using the Authorize.net API, in PHP we create a token request. The data in the request passes customer info, balance, billing address, etc - that data is sent directly with PHP. In response we get a token to be processed in PHP - and then that token is embedded into the HTML form input.
After the credit card form is submitted, we get a javascript json response back to the form to be processed by other JS functions. All works fine until we have a customer with the & in their company name (IE: Bar & Grill)
The & triggers an error only in the json response back to the form - specifically the error we get is: unexpected end of json input which causes the rest of the scripts to error out.
So, the issue is, does the customer data in the PHP token request need to be urlencoded - or is there a special way to handle the json response? From what I can tell, Authorize simply returns the exact customer data in the json response - so if we url encode it on the front end (before the token request is sent), then does that mean we also need to url decode the json response.
Its kind of a chicken and an egg which came first problem.
Authorize.net Token Request (in PHP):
$customerData = new AnetAPI\CustomerDataType();
$customerData->setType("business");
$customerData->setId($ss['authCustID']);
$customerData->setEmail($ii['cEmail']);
// Set the Bill To info for new payment type
$billTo = new AnetAPI\CustomerAddressType();
$billTo->setFirstName($ii['cFirstName']);
$billTo->setLastName($ii['cLastName']);
$billTo->setCompany($ii['cName']); // #1 <----- IE: "Bar & Grill"
$billTo->setAddress($ii['cAddress']. " " .$ii['cAddress1']);
$billTo->setCity($ii['cCity']);
$billTo->setState($ii['cState']);
$billTo->setZip($ii['cZip']);
$billTo->setCountry("USA");
// set shipping profile
$shipTo = clone $billTo ;
// extend billTop profile
$billTo->setFaxNumber('8005551212') ;
$billTo->setPhoneNumber($ii['cPhone']);
//create a transaction
$transactionRequestType = new AnetAPI\TransactionRequestType();
$transactionRequestType->setTransactionType("authCaptureTransaction");
$transactionRequestType->setAmount($ss['balance']);
$transactionRequestType->setCustomer($customerData) ;
$transactionRequestType->setOrder($order) ;
$transactionRequestType->setBillTo($billTo) ;
$transactionRequestType->setShipTo($shipTo) ;
// Build transaction request
$request = new AnetAPI\GetHostedPaymentPageRequest();
$request->setMerchantAuthentication($merchantAuthentication);
$request->setRefId($refId);
$request->setTransactionRequest($transactionRequestType);
//execute request
$controller = new AnetController\GetHostedPaymentPageController($request);
$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::PRODUCTION); // SANDBOX or PRODUCTION
$gToken=[] ;
if (($response != null) && ($response->getMessages()->getResultCode() == "Ok")) {
//echo $response->getToken()."\n";
$gToken["Error"] = 0 ;
$gToken["Token"] = $response->getToken() ;
} else {
//echo "ERROR : Failed to get hosted payment page token\n";
$errorMessages = $response->getMessages()->getMessage();
//echo "RESPONSE : " . $errorMessages[0]->getCode() . " " .$errorMessages[0]->getText() . "\n";
$gToken["Error"] = 1 ;
$gToken["errMsg"] = $errorMessages[0]->getCode() . ": " .$errorMessages[0]->getText() ;
}
Form/JSON response handler:
AuthorizeNetPopup.onReceiveCommunication = function (querystr) {
var params = parseQueryString(querystr);
//console.log(params) ;
switch (params["action"]) {
case "successfulSave":
AuthorizeNetPopup.closePopup();
break;
case "cancel":
AuthorizeNetPopup.closePopup();
break;
case "transactResponse":
// 'response' is a string value
// encode it as an object, to be passed to global function
// that will decode it again for PHP
console.log(params["response"]) ;
var response = JSON.parse(params["response"]); // #2 <--- ERROR: unexpected end of json input
//var response = params["response"];
httpReceipt(response) ;
AuthorizeNetPopup.closePopup();
break;
case "resizeWindow":
var w = parseInt(params["width"]);
var h = parseInt(params["height"]);
var ifrm = document.getElementById("iframeAuthorizeNet");
ifrm.style.width = w.toString() + "px";
ifrm.style.height = h.toString() + "px";
centerPopup();
break;
}
};
Do I url encode data at #1 (in php section) or do I url encode the json response before processing it (at #2) - or both? Very confused on how to handle this. Do we need to encode the data of eachparameter being added to the token request - or can we just encode the entire request before its submitted? Regardless of which end of the communication gets encoding/decoding applied, what are the proper encoding/decoding calls?
UPDATE
To illustrate flow:
paymentPage.html ->PHP generates token, embeds token into page form, also has iframe for paymentPageFrame.html
paymentPageFrame.html -> iFrame communicator page, relays msgs between paymentPage.html and authorize.net
paymentPage.html -> javascript onReceiveCommunication to process messages coming from paymentPageFrame.html
Turns out that authorize.net is returning a URL string to paymentPageFrame.html - the string is not urlencoded. The string is then getting passed back to the parent onReceiveCommunication at which point its being parsed with a custom parser:
function parseQueryString(str) {
var vars = [];
var arr = str.split('&');
var pair;
for (var i = 0; i < arr.length; i++) {
pair = arr[i].split('=');
vars.push(pair[0]);
vars[pair[0]] = unescape(pair[1]);
}
return vars;
}
This custom parser is then causing a data value that has the & in it (IE: "company" : "Bar & Grill") to split the name in half ultimately leading to the invalid/unexpected end of json input.
The string being passsed back to the iFrame, which in turn gets passed to the parent is:
action=transactResponse&response={"accountType":"Visa","accountNumber":"XXXX0623","transId":"62830720474","responseCode":"1","authorization":"185778","shipTo":{"firstName":"Bob","lastName":"Jones","company":"Backyard Bar & Grill","address":"123 Main St ","city":"Tampa","state":"FL","zip":"33606","country":"USA"},"orderDescription":"2020-12-01 bill for All Regions/All Sites","customerId":"1002-0","totalAmount":"1.50","orderInvoiceNumber":"11386-0","dateTime":"2/2/2021 4:57:53 PM","refId":"ref1612285039"}
Now that the string is in the parent page, I am trying to figure the best way to encode it then parse it so it won't break on parsing when a data value has & in it (IE: Backyard Bar & Grill)
So far I am trying, without sucess:
var urlstr = encodeURIComponent(response) ; // encode it first
var newUrl = new URLSearchParams(urlstr) ; // then proper parse it
But when I try to access the parameters, it returns null:
consoole.log(newUrl.get('action')) ;
> null
Your problem is that you split on the & characters which is also inside the JSON response. For a quick solution I suggest something like:
var str = 'action=transactResponse&response={"accountType":"Visa","accountNumber":"XXXX0623","transId":"62830720474","responseCode":"1","authorization":"185778","shipTo":{"firstName":"Bob","lastName":"Jones","company":"Backyard Bar & Grill","address":"123 Main St ","city":"Tampa","state":"FL","zip":"33606","country":"USA"},"orderDescription":"2020-12-01 bill for All Regions/All Sites","customerId":"1002-0","totalAmount":"1.50","orderInvoiceNumber":"11386-0","dateTime":"2/2/2021 4:57:53 PM","refId":"ref1612285039"}';
var response = JSON.parse(str.replace('action=transactResponse&response=', ''));
console.log(response);
console.log(response.shipTo.company);
JS fiddle: https://jsfiddle.net/vx9zr1b7/
This just replaces away the first parameter and the name of the second, so only the value of the second (and thereby the value of "response") will remain. Note that this only works under the assumption that the response is always in this very same format, and does not have any additional parameters in the response.
I suggest you put it inside your case "transactResponse": block.
This will parse you the JSON:
{
accountNumber: "XXXX0623",
accountType: "Visa",
authorization: "185778",
customerId: "1002-0",
dateTime: "2/2/2021 4:57:53 PM",
orderDescription: "2020-12-01 bill for All Regions/All Sites",
orderInvoiceNumber: "11386-0",
refId: "ref1612285039",
responseCode: "1",
shipTo: {
address: "123 Main St ",
city: "Tampa",
company: "Backyard Bar & Grill",
country: "USA",
firstName: "Bob",
lastName: "Jones",
state: "FL",
zip: "33606"
},
totalAmount: "1.50",
transId: "62830720474"
}
Note that the & became an & in the process of parsing the JSON. Therefore, if you are doing anything else with it than just displaying it in the browser, I suggest you html_entity_decode() the value on the PHP side.
After much tinkering around, i finally wrote my own parser that:
A: if exists, capture the response JSON first
B: then parse the remainder of the URL params:
C: return all params and response object as a single object
var str = 'action=transactResponse&response={"accountType":"Visa","accountNumber":"XXXX0623","transId":"62830720474","responseCode":"1","authorization":"185778","shipTo":{"firstName":"Preston","lastName":"Rolinger","company":"Backyard & Grill","address":"2808 W Foster Ave S ","city":"Tampa","state":"FL","zip":"33611","country":"USA"},"orderDescription":"2020-12-01 bill for All Regions/All Sites","customerId":"1002-0","totalAmount":"1.50","orderInvoiceNumber":"11386-0","dateTime":"2/2/2021 4:57:53 PM","refId":"ref1612285039"}&moreKey="other value"' ;
function parseResponse(str) {
var resInfo = [], res = {} ;
if (str.match("&response=")) {
var params = str.split("&response=") ; // leading params & response obj
if (params[1].match("}&")) {
resInfo = params[1].split("}&") ; // splits off anything at end of obj
res.response = JSON.parse(resInfo[0] + "}") ; // add } to complete obj string again
} else {
res.response = JSON.parse(params[1]) ; // else it already is the json string
}
if (resInfo[1]) {
params = params[0]+ "&" +resInfo[1] ; // join url params back together
} else {
params = params[0] ;
}
} else {
params = str ; // else the str has no "response" in it, process just params
}
params = new URLSearchParams(encodeURI(params)) ; //encode then parse
params.forEach(function(value, key) {
res[key] = value ;
}) ;
return res ;
}
var response = parseResponse(str) ;
console.log(response) ;

Parsing a JSON sub string

I have javascript function that calls an external Api and returns in most case a valid JSON string.
function (successResponse) {
{
console.log(successResponse);
}
However, in some cases it return the the following invalid JSON
Response: Status=200, Text: {"createdTime":"2017-05-08T14:47:56Z","lastUpdatedTime":"2017-05-08T14:47:56Z","createdMode":"API","uuid":"e333c1-3599-36d7-9ef5-dc22c79a4a52","userId":"anonymous"}, Error Message: null
How can I parse the above string to get the 'uuid'
Thanks
If you're expecting a response string in that format, you can use a regular expression to extract the "text" portion of the response:
function (successResponse) {
{
var responseText = successResponse.match(/\{.+\}/);
var responseTextJSON = JSON.parse(responseText);
var uuid = responseTextJSON.uuid;
console.log(uuid);
}
Maybe you can parse the string yourself to exclude everything outside of {} ?
var apiResponse = 'Response: Status=200, Text: {"createdTime":"2017-05-08T14:47:56Z","lastUpdatedTime":"2017-05-08T14:47:56Z","createdMode":"API","uuid":"e333c1-3599-36d7-9ef5-dc22c79a4a52","userId":"anonymous"}, Error Message: null';
var apiResponse_fixed = apiResponse.substring((apiResponse.indexOf("{") - 1), (apiResponse.lastIndexOf("}") + 1));
var json_obj = JSON.parse(apiResponse_fixed);
console.log(json_obj.uuid);
Replace the non-JSON features, and then interpret as JSON
Looks like the server owner has been a bit lazy, and programmed an error response which contains a JSON-like interior section but surrounded by a couple of non-JSON elements.
If you are desperate to resolve the situation and have no ability to fix the server output format, here is my suggestion:
notQuiteJson = 'Response: Status=200, Text: {"createdTime":"2017-05-08T14:47:56Z","lastUpdatedTime":"2017-05-08T14:47:56Z","createdMode":"API","uuid":"e333c1-3599-36d7-9ef5-dc22c79a4a52","userId":"anonymous"}, Error Message: null';
madeJson = notQuiteJson.replace('Response: Status=200, Text:','{"Response": {"Status":200}, "Text":').replace('Error Message: null','"ErrorMessage": null}')
obj = JSON.parse(madeJson)
console.log(obj.Text.uuid) // Result: "e333c1-3599-36d7-9ef5-dc22c79a4a52"
Of course this only works if the error message is always exactly this. In reality you may want to use a 3-digit wildcard to cover a range of "Status=" codes. But then you would have to also be confident that all the error modes produce the same non-JSON text at the start and end of the response.
Disclaimer
#sp00m and #Bergi, don't kill me: you are right of course, but this is just for if the poster has no choice in the matter 8-)

JSON String - more than two parameters - receiving null at servlet

I am passing two JSON objects from jQuery - ajax call to servlet using JSON Stringify. But I am getting null. If I pass one Object I am getting expected data but I'm not able to receive two objects. Please help me to find my mistake.
$.ajax({
url : 'insertserv1',
type: 'POST',
dataType: 'json',
data: JSON.stringify({"test1" :masterdata,"test2" :InspTableArray}),
contentType: 'application/json',
mimeType: 'application/json',
success : function(data) {
alert('Hi');
}
});
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
if (br != null) {
json = br.readLine();
}
System.out.println(json); // getting expected data as {"test1":{"grn":"55555","pono":"888888","row":1},"test2":["Type/,"As ","ok","ok","ok","ok","ok"]}
try {
JSONObject rawdata = new JSONObject(json);
JSONObject datat1 = rawdata.getJSONObject("test1");
JSONObject datat2 = rawdata.getJSONObject("test2");
System.out.println(datat1); // return nulls
System.out.println(datat2); // return nulls
The JSON that is being sent in the InspTableArray is invalid so when you try and parse it in Java it breaks:
{"test1":{"grn":"55555","pono":"888888","row":1},"test2":["Type/,"As ","ok","ok","ok","ok","ok"]}
// Problem is this character here --------------------------^
// which breaks the JSON Array of strings
// The value should be "Type" instead of "Type/
// and is likely causing a SyntaxError: Unexpected token A in JSON at position 66
test2 seems to be an array of strings, apart from the first element which isn't a String and causes the rest of the Array to break and should be:
"test2":["Type","As ","ok","ok","ok","ok","ok"]
// ^------ forward slash replaced with closing double-quotation mark

JSON parse valid rows of invalid string

I need to parse a json string with JSON.parse() but somethimes the input is not in the full format. for examle:
{
"x" : "x",
"x1" : "x1",
"x2" : "x2,
"x3" :
And the parsing is breaking obviously. But in this case I want to "save" the valid rows.
Is it possible?
Here is what you can do:
String.prototype.safeParser = function(){
try{
var that=this;
return JSON.parse(this);
}
catch(err){
if(this.length<3){
return {};
}
else if(this.charAt(this.length - 1) == "}"){
that = this.substring(0, this.length - 2) + "}";
}
else{
that = this.substring(0, this.length - 1) + "}";
}
return that.safeParser();
}
}
and use it like console.log(json_string.safeParser());
It checks whether the string is valid json, if it is not, it looks if it ends with curly braces, it removes one character at a time until it is valid json.
Note: this specific code only works for objects with curly braces, not arrays with square brackets. However, this might not be too hard to implement.
JS Fiddle Demo (open your console)

ExtJS decode method fails to decode "&quot" After File Upload

I have a JSON format result sent back to the client that hold the $quot sign. for some unknown reason the code breaks.
Here is the code that bricks from ext-all-debug:
doDecode = function(json){
return eval("(" + json + ")"); FAILS HERE
},
Here is my JSON as it left the server (As far as I know , I hope the server doesn't take the time to decode this &quot on its free time.):
{
success: true,
total: 1,
results: [{
"ID": -1,
"Value": "POChangeRequestlblCustomerCatalogNumber",
"Description": "",
"Labels": {
"1": {
"ID": -1,
"LanguageID": 1,
"Value": "Catalog Number",
"ToolTip": "",
"LanguageName": "English",
"KeyID": -1,
"KeyValue": "POChangeRequestlblCustomerCatalogNumber",
"KeyDescription": ""
},
"2": {
"ID": -1,
"LanguageID": 2,
"Value": """, <<< THIS IS THE BAD PART!!!
"ToolTip": "",
"LanguageName": "Hebrew",
"KeyID": -1,
"KeyValue": "POChangeRequestlblCustomerCatalogNumber",
"KeyDescription": ""
}
},
"ServerComments": "1"
}]
}
this JSON is sent in a text/html content type as it is the result of a file upload operation. could that be part of the problem?
Ok, I have continued to trace down the problem and found that ExtJS does this function on the returned value from a hidden iframe:
doFormUpload : function(o, ps, url){
...
try{
doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
if(doc){
if(doc.body){
if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){
r.responseText = firstChild.value;
}else{
r.responseText = doc.body.innerHTML; << THIS IS WHERE MY " get decoded back to " (sign)
}
}
r.responseXML = doc.XMLDocument || doc;
}
}
catch(e) {}
...
}
Is there a good workaround for this issue. it seems that the browser automatically decodes the value???? any one???? this is a major issue !!
Here is how I worked around it.
The problem was that all browsers automatically decode the & quot; signs.
So I have fixed the Ext doFormUpload function to look like this:
doFormUpload : function(o, ps, url){
...
try{
doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
if(doc){
if(doc.body){
if(doc.body.innerText){
r.responseText = doc.body.innerText;
}else{
r.responseText = doc.body.innerHTML.replace(/<pre>/ig,'').replace(/<\/pre>/ig,'');
}
}
r.responseXML = doc.XMLDocument || doc;
}
}
catch(e) {}
...
}
In addition from now on the content type that the server is returning is "text/plain"
this prevents the browsers from decoding the data.
I also added a little workaround from FF that does not support innerText property but adds the tag that wraps the response.
This is an ugly hack to the ExJS framwork but it worked for me.
Hopefully someone will notice the question and have some better idea on how to solve it.
It doesn't look like the encoded quote is causing your issue -- take a look at this jsfiddle to see that the Ext.decode function works perfectly fine when decoding a JSON string containing ":
http://jsfiddle.net/MXVvR/
Are you sure that the server is returning a JSON string and not a JSON object? Inspect the server response using Firebug, Fiddler, or Chrome Developer Tools to see exactly what's coming back from the server.

Categories

Resources