I am working on a project in that java script as front-end and java as back-end are used, my problem is that I want to pass some string using restangular calls to my back-end resources. If passing parameter have space between the string then I got 500 (Server Error) before reaching to back-end resource side.
Lets take example :
At Java Script : RESTangular call
var myRestCall= Restangular.all('myRoot/myMethod/'+myLocalPath+'/'+folderName);
restPSTFolders.getList().then(function(listPSTFolders){
//my stuff
});
At Java Resource :
#ApiOperation(value = "My Method",
notes = "Returns My Method list",
responseContainer = "List",
response = List.class)
#Path("/myMethod/{myLocalPath}/{folderName}")
#GET
#Transactional
#Timed
public List myMethod(#PathParam("myLocalPath") String myLocalPath, #PathParam("folderName") String sFolderName) {
//my stuff
}
In my example myLocalPath parameter can have spaces and special characters in the string as it can be any :
C:\MY DRIVE\My Path One\My Path
D:\My favorite
To pass this to back-end class from RESTangular call, I need to replace all spaces with some character, it work for me, but I am not thinking its a good way to encode the special character and space with any character because the replacing character can also be a part of existing path then at back-end on again replacing the character, might change the path.
EDIT : If I passed the parameter as json object:
var parameterJsonPath = {};
parameterJsonPath={"myLocalPath": pathValue};
var myRestCall= Restangular.all('myRoot/myMethod/'+parameterJsonPath+'/'+folderName);
Does not make any sense as I got : ../myRoot/myMethod/%5Bobject%20Object%5D Failed to load resource: the server responded with a status of 500 (Server Error)
And making the parameterJsonPath to JSON.stringify(parameterJsonPath); will pass this as string that of no use for me.
Thus in all, is there any good way to encode the special character of string in js, so at back-end side I could decode that string using same key that were used while encoding?
Related
I have picked up a legacy project and I am in the process of debugging something.
I have come across a custom JavaScript function (encodeJsonIntoString) which encode URI components for JavaScript object before sending over via AJAX.
The AJAX is nothing fancy:
$.ajax({
url: URL,
method: 'POST',
datatype : 'json',
data : encodeJsonIntoString(myObj),
success: ...
});
There is no custom processData or contentType set in the ajax call. What really puzzle me is why the previous developers didn't let $.ajax's data attribute to convert the JavaScript object automatically into a URI-encoded string or didn't even try using JQuery.param() to do it but to write the whole function themselves.
For a test, I have made a simple object to test the function encodeJsonIntoString:
var testDataA = {
list: [
{
lastname:"Smith",
firstname:"John"
},
{
lastname:"Black",
firstname:"Jack"
},
{
lastname:null,
firstname:"Mary"
}
]
};
After decoding URI components, the result of the function is:
list[0][lastname=Smith&list[0][firstname=John&
list[1][lastname=Black&list[1][firstname=Jack&
list[2][lastname=null&list[2][firstname=Mary
Notice there are lack of closing square brackets(]) in some places and it uses "null" for null values.
If I run JQuery.param() and decode it, I get this:
list[0][lastname]=Smith&list[0][firstname]=John&
list[1][lastname]=Black&list[1][firstname]=Jack&
list[2][lastname]=&list[2][firstname]=Mary
See the difference? But somehow the result of the function is accepted by the server(Java/Spring - #ModelAttribute) and read into the correct list structure.
I don't have access to the server side here, but I wonder if that array syntax is correctly acceptable or is it just "tolerated" by the server? Will the server see both versions of object in the same structure format?
I am tempted to just replace it with JQuery.param() to handle more robust input data in the future which may also accept special characters.
I am new to REST API's.
I am developing a REST API.
In the following API the parameters I take is cloud-id.
This is the API Call:
#GET
#Path("{cloud-id}")
#Produces("application/json")
public Object Getall(#PathParam("cloud-id") String cloudID) {
if(cloudID!=null){
//return some details
}else{
//return something else
}
}
Happy Path:
http://example.com/sampleCloudID
This also works fine
http://example.com/(sampleCloudID)
It gives a 404 as expected
But when I give the URI as
http://example.com/{sampleCloudID}
ERROR:
You specified too few path parameters in the request.
In case the input I receive is {samplecloudID} I expect the service to return a 404, but I am unable to reach my resource if the path variable is in {}.
Why are curly braces giving me a error but normal parenthesis give 404 as expected ?
If you need to send special characters as part of the URL you need to encode them.
try using http://example.com/%7BsampleCloudID%7D
This should let your controller get the {}
This wikipedia article should give you details.
RFC 1738 states that certain characters are unsafe in URLs:
Unsafe:
Characters can be unsafe for a number of reasons. [...] Other
characters are unsafe because gateways and other transport agents are
known to sometimes modify such characters. These characters are "{",
"}", "|", "", "^", "~", "[", "]", and "`".
All unsafe characters must always be encoded within a URL. For
example, the character "#" must be encoded within URLs even in systems
that do not normally deal with fragment or anchor identifiers, so that
if the URL is copied into another system that does use them, it will
not be necessary to change the URL encoding.
source: https://meta.stackexchange.com/questions/79057/curly-brackets-in-urls?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
You could write code this way in which you did't get any error on changing type of your path variable
#GetMapping(value = { "/your-path/{cloud-id}", produces = "application/json")
public Object Getall(#PathVariable(value = "cloud-id", required = false) String cloudID) {
//do your stuff
}
public Response getCustomerByName(
#PathParam("customerName") String customerName)
Problem :
I am passing customerName as : stack overflow (URL is encoded as : stack%20overflow). I want to receive as decoded string (stack overflow, without %20) in my java code.
What I tried :
This works perfectly fine, but I felt it is not more generic way of doing it.
URLDecoder.decode(customerName, "UTF-8");
Require more generic solution :
I want to do the similar changes in rest of the APIs as well, so using URLDecoder in each API is burden . Is there any common practice which I can follow to impose this decoding at application level? (#PathParam is already decoded when I receive the request)
It shall be auto "Decoded" and you don't need explicit decoding using URLDecoder.decode(customerName, "UTF-8");
As mentioned in javadoc of PathParam javadoc:
The value is URL decoded unless this is disabled using the Encoded annotation.
I just verified below and it works as per javadoc (in weblogic server)
#GET
#Produces(value = { "text/plain"})
#Path("{customerName}")
public Response getCustomerByName(#PathParam("customerName") String customerName) {
System.out.println(customerName);
return Response.ok().entity(customerName).type("text/plain").build();
}
I have my application url which I am sending the the end user on their emails.
Now that url contains the 'username' field, which can contains '#' character.
For e.g. link which sent to the end user :
http://localhost:8080/my-app/someaction/activateuser/abc#def.com/somedata/
Now whenever user clicks on above link, its throwing following exception :
java.lang.IllegalArgumentException
Input string 'abc#def.com' is not valid; the character '#' at position 4 is not valid.
at org.apache.tapestry5.internal.services.URLEncoderImpl.decode(URLEncoderImpl.java:144)
at $URLEncoder_137022607d9.decode($URLEncoder_137022607d9.java)
at org.apache.tapestry5.internal.services.ContextPathEncoderImpl.decodePath(ContextPathEncoderImpl.java:92)
at $ContextPathEncoder_137022607cd.decodePath($ContextPathEncoder_137022607cd.java)
at org.apache.tapestry5.internal.services.ComponentEventLinkEncoderImpl.checkIfPage(ComponentEventLinkEncoderImpl.java:328)
at org.apache.tapestry5.internal.services.ComponentEventLinkEncoderImpl.decodePageRenderRequest(ComponentEventLinkEncoderImpl.java:307)
at org.apache.tapestry5.internal.services.linktransform.LinkTransformerInterceptor.decodePageRenderRequest(LinkTransformerInterceptor.java:68)
at $ComponentEventLinkEncoder_137022607c1.decodePageRenderRequest($ComponentEventLinkEncoder_137022607c1.java)
at org.apache.tapestry5.internal.services.PageRenderDispatcher.dispatch(PageRenderDispatcher.java:41)
at $Dispatcher_137022607c2.dispatch($Dispatcher_137022607c2.java)
at $Dispatcher_137022607bd.dispatch($Dispatcher_137022607bd.java)
at org.apache.tapestry5.services.TapestryModule$RequestHandlerTerminator.service(TapestryModule.java:321)
at org.apache.tapestry5.internal.services.RequestErrorFilter.service(RequestErrorFilter.java:26)
Is there any way to handle such scenario, like encoding/decoding the urls ?
You cannot have an # in the url, because it's a reserved character (the specific RFC is RFC 3986).
You can use the URLEncoder class to encode the url to an acceptable value
As MiniBill has already answered, that can't work, and as Howard has added, Tapestry has its own encoder for URLs. This means that the easiest way for you to get a URL in the format that Tapestry can read is to have Tapestry create it, and then pass it to the component that sends your emails:
#Inject
private LinkSource linkSource;
#OnEvent(...)
void sendActivationEmail() {
final Link activationLink = this.createUserActivationLink(email, otherStuff);
this.activationEmailSender.sendWithActivationLink(email, activationLink);
}
private Link createUserActivationLink(String email, String otherStuff) {
return linkSource.createPageRenderLink(
"someaction/activateuser", false, email, otherStuff);
}
I was able to solve the problem by encoding my string to Base64, and unpacking on Tapestry Java side. My strings were of UTF-8 encoded characters.
I modified the Base64 encoder from this answer: https://stackoverflow.com/a/40392850/5339857
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
})).replace(/\=+$/, '');
}
(just added the .replace in the end, to remove padding =s that Tapestry doesn't like)
And in the Java side the decoding was a breeze: (this example is of an ajax click from javascript - where the Base64 encoding happens)
#OnEvent(value = "clickAjax")
Object clickAjax(String parameter) {
somePagePropetry = new String(java.util.Base64.getDecoder().decode(parameter));
return this;
}
For a very simple ajax name lookup, I'm sending an id from the client webpage to the server (Tomcat 5.5, Java 5), looking it up in a database and returning a string, which is assigned to a javascript variable back in the client (and then displayed).
The javascript code that receives the value is pretty standard:
//client code - javascript
xmlHttp.onreadystatechange=function() {
if (xmlHttp.readyState==4) {
var result = xmlHttp.responseText;
alert(result);
...
}
...
}
To return the string, I originally had this in the server:
//server code - java
myString = "...";
out.write(myString.getBytes("UTF-8"));
Which worked perfectly, if unsafe. Later, I replaced it with:
import org.apache.commons.lang.StringEscapeUtils;
...
myString = "...";
out.write(StringEscapeUtils.escapeJavaScript(myString).getBytes("UTF-8"));
But while safer, the resulting string can't be properly displayed if it contains special chars like "ñ".
For instance, using:
escapeJavaScript("años").getBytes("UTF-8");
sends:
an\u00F1os
to the client.
The question: is there a simple way to parse the resulting string in Javascript or is there an alternate escape function I can use in java that would prevent this issue?
The following works in every browser I've tried:
javascript:alert("a\u00F1os");
Perhaps your string is being escaped twice by mistake.
Actually, now that I read it over, I think I actually don't need to escape the string I'm sending back at all... That is, StringEscapeUtils.escapeJavaScript would be useful if the resulting value was printed in the page, like:
//javascript code with inline struts
var myJavasriptString = "<%=myJavaString%>";
Or am I missing something and there would still be a valid reason to do the escape in the original case? (when it is returned as a series of bytes back to an ajax onreadystatechange handler and assigned to a js variable)