I have an array in javascript that I am trying to pass to my mobilefirst java adapter. I call my adapter like so,
myArr = [1,2,3];
var sendPost = new WLResourceRequest(
"/adapters/MyAdpater/path",
WLResourceRequest.POST
);
var formParam = {"arr":myArr};
sendTicketPost.sendFormParameters(formParams);
Then in my adapter I can have my method and get the param
public JSONObject postAdapterFx(#FormParam("arr") List<Integer> myArray) {}
Currently when I send this I just get a 400 error and it is because the adapter doesnt like the form param as that type, so what else could I set myArray to in the adapter? I can send it as a string and then convert the string to a List<Integer> in the java but that is really messy and I would like to avoid doing that.
So how can I pass this array?
Thanks for the help
you can do it in body with request.send(yourArray). Then you can read it in Java with buffer.
Example from knowledge center
var request = WLResourceRequest(url, method, timeout);
request.send(json).then(
function(response) {
// success flow
},
function(error) {
// fail flow
}
);
You will need to take an extra step before sending the form data to the adapter. sendFormParameters only accepts objects with simple values i.e., string, integer, and boolean; in your case arr is an array.
Create a utility function that will encode the form data, you can use the following:
function encodeFormData(data) {
var encoded = '';
for(var key in data) {
var value = data[key];
if(value instanceof Array) {
encoded += encodeURI(key+'='+value.join('&'+key+'='));
} else {
encoded += encodeURI(key+'='+value);
}
encoded += '&';
}
return encoded.slice(0, -1);
}
Then you will need to update your code as follows:
var myArr = [9,2,3];
var sendPost = new WLResourceRequest("/adapters/Cool/users/cool", WLResourceRequest.POST);
var formParam = {"arr" : myArr};
sendPost.sendFormParameters(encodeFormData(formParam));
Related
I am attempting to do this: Insert a http validation token into serialized JSON data. I already have working the ability to pass it normally in JSON and also to pass it in a header using a custom authorization extension. What I would like to do is, in the validator, if the request isn't in the header data or in the form data, deserialize the passed data and look in there. I can't actually find the data in the request though. When I read the passed data (84 bytes), i just ended up with a bunch of numbers.
Here's the validator for antiforgery:
namespace DispatchCrude.Extensions
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true)]
public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
//try header first
var token = httpContext.Request.Headers["__RequestVerificationToken"];
//try normal method
if (token == null)
{
for(int cl = 0; cl < httpContext.Request.Form.Keys.Count; cl++)
{
if (httpContext.Request.Form.Keys[cl] == "__RequestVerificationToken")
{
token = httpContext.Request.Form[httpContext.Request.Form.Keys[cl]];
}
}
}
if (token == null)
{
//this section isn't finding the passed data
//get here if form stringified
System.IO.Stream str; String strmContents;
Int32 counter, strLen, strRead;
// Create a Stream object.
str = httpContext.Request.InputStream;
// Find number of bytes in stream.
strLen = Convert.ToInt32(str.Length);
// Create a byte array.
byte[] strArr = new byte[strLen];
// Read stream into byte array.
strRead = str.Read(strArr, 0, strLen);
// Convert byte array to a text string.
strmContents = "";
for (counter = 0; counter < strLen; counter++)
{
strmContents = strmContents + strArr[counter].ToString();
}
token = strmContents; //just so i can debug the returned token
}
//if both fail, attempt to check stringified data for matching token.
AntiForgery.Validate(cookie != null ? cookie.Value : null, token);
}
}
}
and here's some example code we are serializing the form data:
$.ajax({
type: "POST",
headers: appendVerificationToken(),
url: "/OrderSettlement/SessionApplyRatesCancel",
data: JSON.stringify({ key: data.key }),
contentType: "application/json",
success: function () {
/* decided to NOT close the window (just cancel and show the [CANCELLED] description)
// on success, close the owning popup
runFuncByNameSingleParameter(_owningPopup.Close);
*/
}
});
As I said, passing it in the header works, but I would like to be able to add it to the data instead and I can't find it in the request to parse it.
thanks to Ouroborus, I was able to come up with a solution.
This works:
string json;
var position = httpContext.Request.InputStream.Position;
using (var reader = new StreamReader(httpContext.Request.InputStream, Encoding.UTF8, false, 8192, true))
{
json = reader.ReadToEnd();
//you MUST reset the input stream to start or you will break post.
httpContext.Request.InputStream.Seek(position, SeekOrigin.Begin);
try
{
var jsonObj = Json.Decode(json); //attempt to parse into json object.
token = jsonObj["__RequestVerificationToken"];
}
catch
{
//eat the parse errors. That simply means it's not json.
}
}
I hope it helps someone else. Note that you must reset the stream back to zero, exactly how I'm doing it, or the controller function won't receive any passed data.
im writing a websocket client and i would like to receive messages as json strings. For this I need a login. And if the login isn't true i send a json string with nosuccess.
JSON String:
{"action":"login","args":["nosuccess"]}
On the client I'm using this to get the string:
WebSocket socket = new WebSocket("ws://localhost:2555/api");
socket.onmessage = function(evt) {
console.log(evt.data);
console.log(typeof(evt.data));
onMessage(evt);
}
function onMessage(evt) {
var data = JSON.parse(evt.data);
var action = data.action;
var args = data.args;
console.log(data);
console.log(typeof(data));
console.log(action);
console.log(args);
But the type of data is a string...
But why?
evt.data returns:
"{\"action\":\"login\",\"args\":[\"nosuccess\"]}"
data returns:
{"action":"login","args":["nosuccess"]}
The WebSocket server is a jetty Server which sends a string and a string array in json parsed in json with gson.toJson(class) Gson by Google. The Class is a class containing String action and String array args.
Complete source code of websocket.js:
var socket;
function openWebsocket(adress) {
socket = new WebSocket(adress);
socket.onopen = function(evt) {
console.log("Socket opened [" + adress + "]");
};
socket.onclose = function(evt) {
loadPage("login.html");
console.log("Socket closed [" + evt.code + "]");
}
socket.onmessage = function(evt) {
onMessage(evt);
}
socket.onerror = function(evt) {
console.log("Socket couldn't connect [" + evt.message + "]");
showMessage("fa-exclamation-circle", "Socket couldn't be established!", 1000);
}
}
function onMessage(evt) {
var data = JSON.parse(evt.data);
var action = data.action;
var args = data.args;
console.log(data);
console.log(typeof(data));
console.log(action);
console.log(args);
$(".card-container h3").html(data);
if(action == "login") {
if(args[0] == "success") {
loadPage("dashboard.htm");
currentpage = "dashboard.htm";
showMessage("fa-check", "Du wurdest erfolgreich eingeloggt", 2000);
} else if(args[0] == "nosuccess") {
loadPage("login.html");
currentpage = "login.html";
showMessage("fa-exclamation-circle", "Falscher Benutzername oder falsches Passwort", 2000);
} else if(args[0] == "unauthenticated") {
loadPage("login.html");
currentpage = "login.html";
showMessage("fa-exclamation-circle", "Login failure: not authenticated", 2000);
}
}
}
function sendMessage(json) {
$(".card-container h3").html(JSON.stringify(json));
console.log(JSON.stringify(json));
socket.send(JSON.stringify(json));
}
If I change this line:
var data = JSON.parse(evt.data);
to this:
var data = JSON.parse("{\"action\":\"login\",\"args\":[\"nosuccess\"]}");
Then it is a json object, but when I use evt.data then it is a string.
If I change the line to this:
var data = JSON.parse(JSON.parse(evt.data));
Then it works, but why, normally it should do it with only one JSON.parse, should it?
This seems to be fairly consistent with over-stringified strings. For example I loaded a text file using FileReader.readAsText that came with \n and \r which rendered in the console, so I did - (JSON.stringify(reader.result)).replace(/(?:\\[rn])+/g, '') first to see the symbols, then to get rid of them. Taking that and running JSON.parse() on it converts it to a non-escaped string, so running JSON.parse() again creates an object.
If you do not stringify your string, it will convert to an object and often it is not necessary but if you have no control over the obtained value, then running JSON.parse() twice will do the trick.
#DerpSuperleggera is correct. The issue was indeed an over-stringified string
let arr = "[\"~#iM\",[\"is_logged_out_token\",false,\"token_type\",\"Bearer\"]]"
So to parse it as an object, I just ran it through JSON.parse twice and that did the trick!
let obj = JSON.parse(JSON.parse(arr))
As others have stated in the comments it seems that this issue has been solved. If you are receiving a response from the server as a "stringified object" then you can turn it into a normal object with JSON.parse() like so:
var stringResponse = '{"action":"login","args":["nosuccess"]}';
var objResponse = JSON.parse(stringResponse);
console.log(objResponse.args);
You can also try out the above code here.
As for why the server is returning a string when you really wanted an object, that really comes down to your backend code, what library you are using, and the transport protocol. If you just want your front-end code to work, use JSON.parse. If you want to edit how the backend responds, please provide more information.
The checked response is correct in that it seems to be an issue of over-stringified strings. I came across it from using AWS Amplify AWSJSON type in my project. The solution that worked for me was to iterate multiple (twice) to get an object.
Wrote a simple JS function that when used to parse will return an object. There isn't really error checking, but a starting point.
export function jsonParser(blob) {
let parsed = JSON.parse(blob);
if (typeof parsed === 'string') parsed = jsonParser(parsed);
return parsed;
}
I am making an ajax call in my javascript submit function. In this ajax call, I am passing an array(globalSelection) as data to the servlet. This array consists elements of function textSelection which is also pasted below.
globalSelection =[];
function submit() {
console.log("globalSelection start")
console.log(globalSelection)
console.log("globalSelection end")
$.ajax({
async : false,
type : "POST",
url : 'http://example.com:8080/myApp/DataServlet',
data: {globalSelection:globalSelection},
success : function(data) {
alert(data)
},
error : function(data, status, er) {
alert("error: " + data + " status: " + status + " er:" + er);
}
});
}
function textSelection(range, anchorNode, focusNode) {
this.range = range;
this.type = 3;
this.rCollection = [];
this.textContent = encodeURI(range.toString());
this.anchorNode = anchorNode;
this.focusNode = focusNode;
this.selectionId = getRandom();
this.yPOS = getYPOS();
this.getTagName = function(range) {
var el = range.startContainer.parentNode;
return el;
}
this.getTagIndex = function(el) {
var index = $(el.tagName).index(el);
return index;
}
this.simpleText = function(node, range) {
if (!node)
var entry = this.createEntry(this.anchorNode, this.range);
else
var entry = this.createEntry(node, range);
this.rCollection.push(entry);
this.highlight(this.rCollection[0].range);
this.crossIndexCalc();
textSelection._t_list.push(this);
pushto_G_FactualEntry(this);
}
this.compositeText = function() {
this.findSelectionDirection();
var flag = this.splitRanges(this.anchorNode, this.focusNode,
this.range.startOffset, this.range.endOffset);
if (flag == 0) {
for (j in this.rCollection) {
this.highlight(this.rCollection[j].range);
}
}
this.crossIndexCalc();
textSelection._t_list.push(this);
pushto_G_FactualEntry(this);
}
}
I am ading the screen of my browser console below, which prints the globalSelection(array).
In my servlet I am getting this array as follows
String[] arrays = request.getParameterValues("globalSelection[]");
System.out.println(arrays);
Here I am getting null value for arrays.
If I put globalSelection as follows in submit function for simple test to servlet, I am able to get the arrays.
var globalSelection = ["lynk_url", "jsonBody", "lynk_dummy1", "lynk_dummy2", "lynk_name", "lynk_desc", "lynk_flag"];
Why my actual globalSelection is shows null in servlet, what I am doing wrong here.
Try with :
String[] arrays = request.getParameterValues("globalSelection");
System.out.println(arrays);
Because the parameter submitted with name "globalSelection" only not "[]" symbol.
I see your problem and I have a simple solution.
I recommend in that case that you convert the array as a string in JS:
JSON.stringify(globalSelection)
and then reconstructing the object on the backend using some sort of library for JSON conversion like: https://code.google.com/archive/p/json-simple/
You could then do something like this:
JSONArray globalSelection = (JSONArray) new JSONParser().parse(request.getParameter("globalSelection"));
Iterator i = globalSelection.iterator();
while (i.hasNext()) {
JSONObject selection = (JSONObject) i.next();
String type = (String)selection.get("type");
System.out.println(type);
}
This will parse your array and print the selection type. Try it, hope it helps.
This is my C# WebAPI2 controller, which gets hit:
[HttpGet, Route("bycaseidlist/{idArray}")]
public async Task<IHttpActionResult> GetByCaseIdList([FromUri] List<int> idArray)
This is the call:
var idArray = [4,4,2,4];
var url = baseUrl + 'api/cases/bycaseidlist/' + idArray ;
$http.get(url)
The problem is that the API doesn't get the array, it gets ...this:
In other words an array with one value: 0. Why is this happening? How do I fix it? It seems to be in-line with this answer, but it doesn't work. Should I pass it in the body? I feel like I am missing something obvious.
Get ActionMethods can take objects as arguments. However, the default behavior is to look at the body when the parameter is not a .net primitive. In order to force the action method to use a model binder to read the object data from the request, the parameter can be decorated with the [FromUri] or [ModelBinder] attributes. (Note there are other ways to do this that include doing parameter binding rules but that is probably overkill for what you are trying to accomplish here). Here is an implementation that solves the original problem that you were posing.
<script type="text/javascript">
var ajaxCall = function (myArry) {
var ajaxProperties = {};
ajaxProperties.url = "/api/Mul/Mutiply";
ajaxProperties.type = "Get";
ajaxProperties.data = {};
ajaxProperties.data.numbers = myArry;
ajaxProperties.contentType = "application/json";
console.log(ajaxProperties);
ajaxProperties.success = function (data) {
console.log(data);
}
ajaxProperties.error = function (jqXHR) {
console.log(jqXHR);
};
$.ajax(ajaxProperties);
};
var getData = function (e) {
var myArry = new Array();
myArry.push($('input[name=num1').val());
myArry.push($('input[name=num2').val());
ajaxCall(myArry);
return false;
};
</script>
Controller
[HttpGet]
public IHttpActionResult Multiply([FromUri] int[] numbers)
{
int result = 0;
if(numbers.Length > 0)
{
result = 1;
foreach (int i in numbers)
{
result = result * i;
}
}
return Ok(result);
}
}
I think my mistake was using Get. I might be remembering incorrectly (someone confirm if you know offhand), but Get might not be able to take objects as arguments. Anyway, I changed the method to POST and then changed the param to be sent in the request body, rather than the url. It now works. Here is the working code:
[HttpPost, Route("bycaseidlist")]
public async Task<IHttpActionResult> PostByCaseIdList([FromBody] int[] sqlCaseIdArray)
and the call itself:
function runDbCall(url, sqlCaseIdArray){
return $http({
method: 'POST',
url: url,
data: sqlCaseIdArray
});
}
runDbCall(url, sqlCaseIdArray)
I will come back to this when I figure out if the problem was Get not being able to take objects, but I thought it could in url, just not in body...need to clarify. If someone posts an answer just on that part, I will accept, since that's probably the root of the prob.
I'm trying to get my array of URL's to run through a JQuery .get function to get the site's source code into one string outside of the function. My code is below.
var URL = ["http://website.org", "http://anothersite.com"];
var array = URL.map(function(fetch) {
var get = $.get(fetch, function(sourcecode) {
sourcecode = fetch;
}
I need the sourcecode variable to be the combination of source code on all of the URLs in the array.
You need to put a variable outside of the function, something like this data variable below and append to it with +=:
var URL = ["http://website.org", "http://anothersite.com"];
var array = URL.map(function(fetch) {
var data = null;
var get = $.get(fetch, function(sourcecode) {
data += fetch;
}
}
Try this like,
var URL = ["http://website.org", "http://anothersite.com"];
var array = $(URL).map(function(fetch) {
var data='';
$.ajax({
url:fetch,
async:false,
success : function(d){
data=d;
}
});
return data;
}).get();
Since you're using jQuery, I suppose that jQuery.each() may be a better way to iterate over the array.
var URL = ["http://website.org", "http://anothersite.com"];
var str = [];
$.each(URL, function(index, fetch) {
$.get(fetch, function(sourcecode) {
str.push(sourcecode); // if you want an array
})
});
str.join(''); // if you want a string
console.log(str);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>