SpringMVC + @PathVariable 注意事项
问题出现的条件
- 使用@PathVariable 注解
- 该注解绑定的参数位于uri 的最后
- 请求传参时,参数中含有
.
(点)
出现的问题
示例代码:
// TestController.java
@RequestMapping("/test/{param}")
public Result test(@PathVariable("param") String param) {
return new Result();
}
如果需要调用上面的接口,一般可能是GET /test/abc
,此时param 的值应该为abc
。
但是当传入的参数包含点时,spring 会将最后一个点后面的内容截断。比如/test/abc.def.ghi
,则,此时后端拿到的param 的值会被截断为abc.def
。
处理方法
- 可以在该参数后面增加一段,如:
@RequestMapping("/test/{param}/end")
- 可以修改匹配的方式,使用正则匹配,如:
@RequestMapping("/test/{param:.+}")
出现的问题2
上面一个方法可以解决后端取路径中参数不正确的问题,但是经过上面的方法解决之后,当调用接口(如输入一个邮箱12345@qq.com
)后,依旧会报错,并最终返回406,报错如下:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:239)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:873)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:858)
...
这是因为在请求时候,spring 将最后一个点及后面的内容识别成了扩展名。认为请求的是一个文件,但是请求返回的可能是json 串,这时候就出现HttpMediaTypeNotAcceptableException 了。
经初步测试发现,只有当spring 认为这是个文件扩展名时,才会产生错误,如果传入的参数是中文(abc.你好
)或非扩展名结尾(abc.aaa
)等,就不会抛出类型不正确的异常。
但是由于邮箱有很多是以com 结尾,同时又正好又com 扩展名的文件,所以这一点需要注意。
解决方法2
修改spring boot 的配置
详见ContentNegotiationConfigurer
Error 406 while using an email address as a path variable in Spring Boot