问题起因:
通过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() : "");
}