【Feign踩坑】Get传参String中的“;”被转换成“,”问题
例:
发出的请求为http://xxxx?temp=‘dsdd;ffff’。
下游服务接收到的temp参数值将会变成"dsdd,ffff"。
首先,我们知道feign底层使用RequestTemplate进行请求发送
RequestTemplate在发送请求前将会对请求进行转换。
使用resolve方法对GET参数变量进行url拼接。
public RequestTemplate resolve(Map<String, ?> variables) {
StringBuilder uri = new StringBuilder();
/* create a new template form this one, but explicitly */
RequestTemplate resolved = RequestTemplate.from(this);
if (this.uriTemplate == null) {
/* create a new uri template using the default root */
this.uriTemplate = UriTemplate.create("", !this.decodeSlash, this.charset);
}
uri.append(this.uriTemplate.expand(variables));
/*
* for simplicity, combine the queries into the uri and use the resulting uri to seed the
* resolved template.
*/
if (!this.queries.isEmpty()) {
/*
* since we only want to keep resolved query values, reset any queries on the resolved copy
*/
resolved.queries(Collections.emptyMap());
StringBuilder query = new StringBuilder();
Iterator<QueryTemplate> queryTemplates = this.queries.values().iterator();
while (queryTemplates.hasNext()) {
QueryTemplate queryTemplate = queryTemplates.next();
String queryExpanded = queryTemplate.expand(variables);
if (Util.isNotBlank(queryExpanded)) {
query.append(queryExpanded);
if (queryTemplates.hasNext()) {
query.append("&");
}
}
}
String queryString = query.toString();
if (!queryString.isEmpty()) {
Matcher queryMatcher = QUERY_STRING_PATTERN.matcher(uri);
if (queryMatcher.find()) {
/* the uri already has a query, so any additional queries should be appended */
uri.append("&");
} else {
uri.append("?");
}
uri.append(queryString);
}
}
/* add the uri to result */
resolved.uri(uri.toString());
/* headers */
if (!this.headers.isEmpty()) {
/*
* same as the query string, we only want to keep resolved values, so clear the header map on
* the resolved instance
*/
resolved.headers(Collections.emptyMap());
for (HeaderTemplate headerTemplate : this.headers.values()) {
/* resolve the header */
String header = headerTemplate.expand(variables);
if (!header.isEmpty()) {
/* split off the header values and add it to the resolved template */
String headerValues = header.substring(header.indexOf(" ") + 1);
if (!headerValues.isEmpty()) {
resolved.header(headerTemplate.getName(), headerValues);
}
}
}
}
resolved.body(this.body.expand(variables));
/* mark the new template resolved */
resolved.resolved = true;
return resolved;
}
queryTemplate.expand(variables)对整体请求变量进行组装;
public final class QueryTemplate extends Template {
static final String COLLECTION_DELIMITER = ";";
......
@Override
public String expand(Map<String, ?> variables) {
String name = this.name.expand(variables);
return this.queryString(name, super.expand(variables));
}
private String queryString(String name, String values) {
if (this.pure) {
return name;
}
/* covert the comma separated values into a value query string */
List<String> resolved = Arrays.stream(values.split(COLLECTION_DELIMITER))
.filter(Objects::nonNull)
.filter(s -> !UNDEF.equalsIgnoreCase(s))
.collect(Collectors.toList());
if (!resolved.isEmpty()) {
return this.collectionFormat.join(name, resolved, this.getCharset()).toString();
}
/* nothing to return, all values are unresolved */
return null;
}
}
由以上代码可见,当我们将参数temp的值设置为“dsdd;ffff”时,使用get请求发送时,将会将query的值转换为temp=dsdd&temp=ffff。
最终发送给下游服务的请求将会变成 http://xxxx?temp=dsdd&temp=ffff。
同时由于springmvc框架的解析方式,GET中同参数变量将会被转成以“,”分割的字符串。因此最终解析出的的temp的值将会变为"dsdd,ffff"。