I've seen a similar issue to this when using Spring MVC #PathValue but none of the solutions online for that worked for this issue.
I am currently working on an app where users will enter a URL and #RequestParam seems to truncate the URL's passed in on ?'s and #'s.
#RequestMapping(value = "/route/path", method = RequestMethod.GET, produces = "application/json")
public Value method(#RequestParam(value="url") String url, HttpServletRequest request) throws Exception {
//execute code
Now for example if someone were to pass in localhost:8080/route/path?url=https://css-tricks.com/hash-tag-links-padding/#article-header-id-0
the query would be truncated to url=https://css-tricks.com/hash-tag-links-padding/
The same thing seems to happen with '&' as well. I've tried a myriad of solutions around regexes, Bean configuration, and overriding configurePathMatch in WebMvcConfigurerAdapter.
Has anyone else had this issue? If so, did you find a work around? Thanks in adavance!
Use encodeURIComponent to encode your parameter url.
You need to use Percent Encoding on the incoming url.
# is %23
? is %3F
Related
My controller methods look like the following:
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String handleSaveRequest(RedirectAttributes redirectAttributes,
Model model) {
redirectAttributes.addFlashAttribute("myFlashAttr", "FOOBAR");
return "redirect:/confirmationpage?myAttr=Some Value";
}
#RequestMapping(value = "/confirmationpage", method = RequestMethod.GET)
public String confirmationPage(#RequestParam String myAttr,
#ModelAttribute("myFlashAttr") String flashAttr,
Model model) {
logger.info("Param: " + myAttr);
logger.info("FlashAttr: " + flashAttr);
// Do Some stuff
return "path/to/confirmation.jsp";
}
I was originally using Spring 4.0 and this was working as expected. When I was redirected to the confirmation page I had myAttr = "Some Value" and flashAttr = "FOOBAR". However after upgrading to Spring 4.3 flashAttr was empty string (ie myAttr = "Some Value" and flashAttr = "").
After shooting in the dark for a bit I found that replacing the whitespace in the redirect URL with "%20" (ie "redirect:/confirmationpage?myAttr=Some%20Value") did the trick. After making this change the log output was myAttr = Some Valu" and flashAttr = FOOBAR as expected.
So I have a few questions really:
What changed between Spring 4.0 and 4.3 that causes this problem?
Why would URL encoding cause problems with session attributes?
What is the "correct" way to handle URL encoding on redirects in Spring MVC 4.3? I was always under the impression that Spring handled this for me in the UrlBasedViewResolver but now I am second-guessing that...
After digging around I found this issue on the Spring JIRA. I was able to use the suggested workaround to solve my problem without having to handle any of the URL encoding myself. The redirect now works as follows:
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String handleSaveRequest(RedirectAttributes redirectAttributes,
Model model) {
redirectAttributes.addFlashAttribute("myFlashAttr", "FOOBAR");
redirectAttributes.addAttribute("myAttr", "Some Value");
return "redirect:/confirmationpage?myAttr={myAttr}";
}
While the issue described did not exactly match my case, it seems that the answer to 2&3 are:
The FlashMapManager relies on a different encoding scheme than the URL encoder in RedirectView.
Using this workaround it forces Spring to use URIUtils to encode each query parameter value.
I still do not understand the answer to my main question of "What changed to cause this?" but for my purposes the posted workaround seems to do the trick.
I have a Spring RestController with a RequestMapping and a PathVariable:
#RequestMapping(value = "/path/{someId:.+}")
public void method(#PathVariable("someId") String someId) {
...
}
When calling this controller, I get a Http 406 Not Acceptable error with requests like:
- /path/id8327.123
- /path/id8327.txt
But not with:
- /path/id8327.234
- /path/id8327.bbb
Isn't that strange?
It was only recently I found out that .txt also failed, so I guess it has something to do with extension mappings.
How can I work around this hidden feature?
Kind regards
You can add a '/' at end of the URL, like:/path/id8327.123/.
This method can help Spring to recognize.
I ran into this issue while calling an endpoint that had an IP #PathVariable at the end.
Apparently, there is an older MediaType: application/vnd.lotus-1-2-3.
Spring tries to determine what the MediaType to return should be and it does this first by finding a possible MediaType extension in the URL.
In this case it finds the extension as the String after the last '.'
For the '123' case Spring thinks that the MediaType should be the value for the MediaType map key '123' which is 'application/vnd.lotus-1-2-3'.
The easy fix is to change #PathVariable into #RequestParam and pass the value as an URL query parameter.
I'm trying to build an API that takes a POST with one parameter in the body that should be x-www-form-urlencoded. I've currently mapped it as:
#RequestMapping(method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = APPLICATION_JSON_VALUE)
public ResponseEntity<LinkEntity> createShortLink(#RequestBody String url) {
LinkEntity savedLink = linkService.create(url);
}
When I do a POST with Postman (REST Chrome extension) with one form parameter url=http://www.drissamri.be it comes into this method as url=http%3A%2F%2Fwww.drissamri.be as expected.
When I try to change the #Requestbody into #RequestParam(value = "url") I still get the URL with the url= prefix (as expected) but it is not urlencoded anymore. Why doesn't the encoding take place any more? Is this a bug or is there another way to take in the parameter as urlencoded value
As correctly mentioned by Pavel Horal the parameter is retrieved by ServletRequest#getParameter and is already decoded. If you need to access the origin parameter you can access the parameter by other means.
One way would be to inject a HttpServletRequest and use HttpServletRequest#getQueryString() which does not decode the values.
I have an application using spring-mvc 3.0.
The controllers are configured like this:
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ModelAndView updateValues(
#RequestParam("einvoiceId") String id){
...}
When posting an id that contains special characters (in this case pipe |), url-encoded with UTF-8 (id=000025D26A01%7C2014174) the string id will contain %7C. I was expecting spring-mvc to url decode the parameter. I am aware that I can solve this by using
java.net.URLDecoder.decode()
but since I have a large number of controllers, I would like this to be done automatically by the framework.
I have configured the Tomcat connector with URIEncoding="UTF-8" and configured a CharacterEncodingFilter, but as I understand it this will only affect GET requests.
Any ideas on how I can make spring-mvc url decode my post parameters?
http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q3
This page says CharacterEncodingFilter can change POST parameters
I believe you encounter the same issue as I did.
Try using #PathVariable instead #RequestParam.
#PathVariable is to obtain some placeholder from the uri (Spring call it an URI Template) — see Spring Reference Chapter 16.3.2.2 URI Template Patterns
If you do, you have to change your url and don't provide parameter 'id'.
Just "/update/000025D26A01%7C2014174".
More information can be found where I found the solution for my problem #RequestParam vs #PathVariable
Given the following request mapping on a Spring MVC controller:
#RequestMapping(method=GET, value="/users/{name}")
ModelAndView findUser(#PathVariable String name) {
...
}
How can I make it accept a #PathVariable with a dash in it?
The following works, passing in fred as the name:
GET /users/fred
However the following does not work, passing in null in place of the name:
GET /users/u-fred
I would appreciate suggestions on how to define the #PathVariable so it can accept dashed strings, for example, u-fred.
Thanks.
I just tested that with my spring-mvc 3.0.5 application and it works fine with a dash:
make sure you are running the latest version
make sure you are tracking the correct request (and not some fake one, for example a forgotten ajax request)