专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringBoot问题--RestTemplate参数类型List问题

问题起因:

通过RestTemplate发起RPC请求。当服务提供者的请求参数为List类型时,消费者接收到的参数为一个不合法的类型,导致消费方会会因为参数的类型不合法导致业务问题。

服务方和消费方参数及类型:

服务方:参数类型List<String>
消费方:参数类型String[]
结果:["[177","187","189","190","191]"]

服务方:参数类型String[]
消费方:参数类型String[]
结果:["177","187","189","190","191"]

源码分析:RestTemplate

//第一步:RestTemplate发起Http请求
RestTemplate internalTemplate = restTemplate;
response = internalTemplate.exchange(expandUrl(fullUrl, params.keySet()),
                        method, httpEntity, String.class, params);

//第二步:
@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
                                      @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables)
        throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    // 执行execute方法
    return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
}

//第三步
@Override
@Nullable
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
                     @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables)
        throws RestClientException {

    URI expanded = getUriTemplateHandler().expand(url, uriVariables);
    return doExecute(expanded, method, requestCallback, responseExtractor);
}

源码分析:DefaultUriBuilderFactory

@Override
public URI build(Map<String, ?> uriVars) {
    if (!defaultUriVariables.isEmpty()) {
        Map<String, Object> map = new HashMap<>();
        map.putAll(defaultUriVariables);
        map.putAll(uriVars);
        uriVars = map;
    }
    if (encodingMode.equals(EncodingMode.VALUES_ONLY)) {
        uriVars = UriUtils.encodeUriVariables(uriVars);
    }
    UriComponents uriComponents = this.uriComponentsBuilder.build().expand(uriVars);
    if (encodingMode.equals(EncodingMode.URI_COMPONENT)) {
        uriComponents = uriComponents.encode();
    }
    return URI.create(uriComponents.toString());
}
源码分析:org.springframework.web.util.HierarchicalUriComponents

@Override
protected HierarchicalUriComponents expandInternal(UriTemplateVariables uriVariables) {
    Assert.state(!this.encoded, "Cannot expand an already encoded UriComponents object");

    String schemeTo = expandUriComponent(getScheme(), uriVariables);
    String fragmentTo = expandUriComponent(getFragment(), uriVariables);
    String userInfoTo = expandUriComponent(this.userInfo, uriVariables);
    String hostTo = expandUriComponent(this.host, uriVariables);
    String portTo = expandUriComponent(this.port, uriVariables);
    PathComponent pathTo = this.path.expand(uriVariables);
    //这一步会处理param
    MultiValueMap<String, String> paramsTo = expandQueryParams(uriVariables);

    return new HierarchicalUriComponents(
            schemeTo, fragmentTo, userInfoTo, hostTo, portTo, pathTo, paramsTo, false, false);
}

private MultiValueMap<String, String> expandQueryParams(UriTemplateVariables variables) {
    int size = this.queryParams.size();
    MultiValueMap<String, String> result = new LinkedMultiValueMap<>(size);
    UriTemplateVariables queryVariables = new QueryUriTemplateVariables(variables);
    this.queryParams.forEach((key, values) -> {
        String name = expandUriComponent(key, queryVariables);
        List<String> expandedValues = new ArrayList<>(values.size());
        for (String value : values) {
            expandedValues.add(expandUriComponent(value, queryVariables));
        }
        result.put(name, expandedValues);
    });
    return result;
}
源码分析:org.springframework.web.util.UriComponents

    @Nullable
    static String expandUriComponent(@Nullable String source, UriTemplateVariables uriVariables) {
        if (source == null) {
            return null;
        }
        if (source.indexOf('{') == -1) {
            return source;
        }
        if (source.indexOf(':') != -1) {
            source = sanitizeSource(source);
        }
        Matcher matcher = NAMES_PATTERN.matcher(source);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String match = matcher.group(1);
            String variableName = getVariableName(match);
            Object variableValue = uriVariables.getValue(variableName);
            if (UriTemplateVariables.SKIP_VALUE.equals(variableValue)) {
                continue;
            }
            //继续处理
            String variableValueString = getVariableValueAsString(variableValue);
            String replacement = Matcher.quoteReplacement(variableValueString);
            matcher.appendReplacement(sb, replacement);
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    private static String getVariableValueAsString(@Nullable Object variableValue) {
        //关键一步,这里将整个param转为了String
        return (variableValue != null ? variableValue.toString() : "");
    }
未经允许不得转载:搜云库技术团队 » SpringBoot问题--RestTemplate参数类型List问题

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们