起因
最近新开发一个基于Spring Boot的后端接口服务,开发完以后打包、运行、发布,然后用postman做一下接口测试,响应没有任何问题,简直完美。于是便给老板说任务已经完成,然后就欢快的下班了。
没想到下班回家屁股还没坐热,老板发来消息,说客户调接口的时候报错。我说不应该呀,然后就打开电脑上线检查问题。又用postman试了一下接口好像没有问题,奇怪了。总不能告诉老板客户对我们接口的使用姿势不对吧。。。那我只好调整一下自己的姿势。
分析问题
仔细检查之下发现自己和客户使用上唯一的区别就是调接口的时候传递的参数可能不同,因为业务需要,我们的参数都是用占位符提前预制好的,格式为:url?param1={param1}¶m2={param2}¶m3={param3},我测试的时候都会替换占位符参数为具体的值,例如url?param1=11¶m2=22¶m3=33,没有任何问题。客户使用的时候有可能替换占位符,也有可能没有替换。那我试一下没有替换的,一试之下,bingo,果然报错了,postman返回400 bad request。
赶紧查看一下后端日志,发现后端没有打印任何日志,仿佛根本就没有接收到这个请求。这就奇怪了,好歹给个报错信息也好分析呀。而且之前的Spring Boot项目也是这么操作的,也有占位符,没有任何问题呀。这次的项目和之前项目的唯一区别就是用的Spring Boot版本不同,这次是用了最新的2.1.5.RELEASE版本。
那唯一的原因就是之前的版本支持请求参数中带有大括号{},2.1.5.RELEASE版本不支持了。谷歌一下,果然是。 RFC 3986规范规定Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。而[]/{}等特殊字符是不支持的,最新版本的server tomcat和undertow遵守了该规范。然后最新版本的Spring Boot又升级到了最新版本的tomcat和undertow,也就自动支持了该规范。
解决思路
知道了原因,解决办法自然就出现了。
- 回退Spring Boot到支持Url含有特殊符号的旧版(怂了);
- 强制客户必须替换请求参数中的占位符(可能被老板骂死);
- 修改新版Spring Boot配置,支持Url含有大括号{}等特殊符号;
解决办法
基于技术人员的骄傲,我还是决定用第三种解决办法。
因为我用的是Spring Boot内置的undertow server,那就改undertow的配置。具体改法是在项目中新增如下配置类即可。
@Component
public class MyWebServerCustomizer implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
@Override
public void customize(UndertowServletWebServerFactory factory) {
factory.addBuilderCustomizers(builder-> builder.setServerOption(UndertowOptions.ALLOW_UNESCAPED_CHARACTERS_IN_URL, Boolean.TRUE));
}
}