踩了个SpringMVC用String数组接收参数的小坑,记录一下,方便以后查询

背景

写了个接口,使用String数组接收一个叫args的参数
请求接口使用的是RestTemplate,想法很简单,实现也简单,使用MultiValueMap攒好了参数直接请求,成功,发版上线,运行了一段时间一直没有问题.

直到最近的一次使用,场景是args的长度只有1个,但是内容中有特殊字符: 英文逗号.
特殊字符是我叫的,本来是没有这个规定的,意会就好.

所以,有问题的请求会发一个类似于下边的请求

curl -XPOST 'http://localhost:8081/api/inner/server/system/alarm' -d 'key=123&args=1,2,3'

期望收到的args = new String[]{“1,2,3”},但是其实收到了 args = new String[]{“1”, “2”, “3”}
问题一目了然,就是SpringMVC在当丁参数的时候进行了切割,本意是大多数场景下接收逗号分隔的字符串都是期望切割的,但是影响了我接收数据

赶紧试一下,发了个 new String[]{“1.2,2”, “”} 的请求,看下,没有切割.

正常的话,我们的请求应该是这个样子

curl -XPOST 'http://localhost:8081/api/inner/server/system/alarm' -d 'key=123&args=1,2,3&args='  

问题基本明确了,赶紧开始debug吧.

查资料我们得知,SpringMVC就系参数得到入口是 RequestMappingHandlerAdapter的invokeHandleMethod方法,就把断点打在这里吧.

首先我们跟着代码单步执行,最后跟到了

org.springframework.core.convert.support.GenericConversionService#convert(Object, TypeDescriptor, TypeDescriptor)  

这个方法

通过之前的一步步组合,最终代码选出了StringToArrayConverter这个类,决定用它来转化.
选择的方式也是根据推断出来的请求参数类型String和反射得到的接口请求参数类型String[]来确定的,变数就是推断的这个String
再跑一遍看看这个推断的过程吧.

还是跟着代码单步执行,最终到了 org.springframework.web.method.annotation.RequestParamMethodArgumentResolver#resolveName

if (arg == null) {
    String[] paramValues = request.getParameterValues(name);
    if (paramValues != null) {
        // 如果数组长度等于1,就直接取出来数据作为参数,否则的话直接用这个数组
        arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
    }
}