Spring Rest Request 406 Not Acceptable for ".123" - java

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.

Related

Spring with Tomcat 7: PUT request returns 403 for strange resons

I have a web application written on Spring 3.1 (not boot) and running on Tomcat 7.
I have a #Controller implements method PUT on a certain URL.
In some cases When sending a PUT request from Postman, I get a 403 response instead of what is expected.
For example:
Sending the request to a non-implemented URL (on GET to the same URL I get a 404)
Sending an invalid JSON as the request body (Expected 400)
Sending a string instead of a numeric request parameter (Expected 400)
I also implement a filter that excepts all requests and just before the filter exists, I can verify I get the expected status from the rest of the chain.
This is an example of a controller code:
#RequestMapping(value = "/{book}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
protected Book put(#PathVariable(value = "bookId") String id, #RequestBody #Valid Book book) {
return book; // just a stub
}
And this is the relevant part in the filter:
filterChain.doFilter(req, res);
// res.getStatus() is the expected status
return; // after this line I move to internal code of Tomcat which I cannot debug, but something happens there.
What do I miss?
Thanks
Check out CORS filter configuration first as Andreas said: https://tomcat.apache.org/tomcat-8.5-doc/config/filter.html
Check out this flowchart also https://tomcat.apache.org/tomcat-8.5-doc/images/cors-flowchart.png
Check out this stackoverflow post finally 403 on JSON PUT request to Tomcat with Spring 3.0.5 and Jackson
Your path variable value is bookId, but your url uses {book}; both should match. Try changing the url to "/{bookId}" or the path variable to #PathVariable(value = "book"). It might be useful to know the URL that you are calling to help analyse the issue.

Missing Request header "Accept" with Spring 5.x

I was using Spring version 4.x, and with the upgrade to 5.x - I have noticed that some of the API requests are failing (MissingRequestHeaderException) if the Accept header is not provided in the request.
The interface doesn't really need them, as it is not being used. The API's without it in the interface works fine. A solution would be to remove it from all the API's wherever it's there. But that's not a path we want to take now, I am looking for a general solution that could be applied to all API's without having to change each one separately.
Is there a way I could ask Spring to ignore this parameter in the interface ?
Or maybe handle the MissingRequestHeaderException so as to ignore it and process the API request, is that possible?
The API Interface:
public Void setEmployeeDetails( #PathVariable( "employeeId" )Integer employeeId, #Valid #RequestBody EDetails eDetails, String accept )
The API Controller implementing the interface:
Void setEmployeeDetails( #ApiParam(value = "ID of the employee.",required=true ) #PathVariable("employeeId") Integer employeeId,
#ApiParam(value = "" ,required=true ) #Valid #RequestBody EDetails eDetails,
#RequestHeader("Accept") String accept)
Javadoc of MissingRequestHeaderException says:
ServletRequestBindingException subclass that indicates that a request header expected in the method parameters of an #RequestMapping method is not present.
Checking the Spring source code, it also seems like that exception is only thrown by RequestHeaderMethodArgumentResolver, which says:
Resolves method arguments annotated with #RequestHeader except for Map arguments. See RequestHeaderMapMethodArgumentResolver for details on Map arguments annotated with #RequestHeader.
An #RequestHeader is a named value resolved from a request header. It has a required flag and a default value to fall back on when the request header does not exist.
So it would seem that if you're getting that error, it's because your code is asking for the Accept header and did not specify required=false, e.g.
#RequestMapping(...)
public void foo(#RequestHeader(name="Accept", required=false) String accept) {
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑
// Missing!
...
}

Spring Boot #RequestParam truncating URL's passed in with ?'s and #'s

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

Why is my Spring service returning any content type requested by client?

I have a Spring rest service using Spring 3.1.0.RELEASE. Here is the relevant code for the service call in question:
#RequestMapping(value="/{var1}", method=RequestMethod.GET, produces="application/json")
#ResponseBody
public String getSomeStuff(#PathVariable final String var1) {
return myJsonString;
}
If I call this using the following curl command, it happily returns me my json string with a content-type of application/xml whereas I would expect a 406 based on the Spring 3.1 docs:
curl -v -H "Accept: application/xml" http://localhost:8080/MyServiceSite/myvalue
There is no extra configuration in my app for this service (no serialization), I am returning raw json with no post-processing for the service configured. I'm certain I have missed something, can anyone point out anything I may have missed?
Edit: Here is the documentation I was looking at when attempting to get this working. Specifically section 16.3.2.5. My code is very similar except that their code looks like it assumes config setup to let Spring handle serialization. Perhaps the produces does not work when bypassing the Spring serialization?
Edit: I changed my expectation for the response code. A 415 would indicate I was sending improper content in my request body whereas 406 is proper for having an accept header that doesn't jive with the content type of the server.
Anyway, I have changed this method do return a Map and added config for it to serialize to json and now if I send an invalid content type from the client I get the proper 406 response. It seems that maybe the "produces" setting is ignored when the output of the method is not being serialized.
The produces condition is new to Spring MVC 3.1 and is only supported with the RequestMappingHandlerMapping and related #MVC support classes, also new in Spring 3.1. My guess is that you're using the 3.0 #MVC support classes, which do not support the produces condition. Your code otherwise is correct and so are your expectations of what should happen.
The use of headers="Accept=application/json" is unnecessary in 3.1. That's exactly what the produces condition was introduced for.
What about the headers attribute for the #RequestMapping. You could set the Accept header in there. Something like:
#RequestMapping(value="/{var1}", method=RequestMethod.GET, produces="application/json", headers = "Accept=application/json")
#ResponseBody
public String getSomeStuff(#PathVariable final String var1) {
return myJsonString;
}
I don't know how Spring would handle a request to that path without a matching header. If it doesn't give what you want you might need to define a similar mapping without the headers and have it send back a ResponseEntity and set the response code or something, but I would hope it would handle it appropriately.

Handling special characters in post parameters for Spring-mvc

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

Categories