feign-core 版本
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-core -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.4.0</version>
</dependency>
调用路径
源码分析
1. Template 类
package feign.template;
...
public class Template {
protected String resolveExpression(Expression expression, Map<String, ?> variables) {
String resolved = null;
Object value = variables.get(expression.getName());
// 1. 调用 SimpleExpression 的 expand() 方法
return expression.expand(value, this.encode.isEncodingRequired());
}
}
public final class Expressions {
static class SimpleExpression extends Expression {
private final FragmentType type;
String encode(Object value) {
// 2. 调用 UriUtils.encodeReserved() 方法,type 参数是 FragmentType.PATH_SEGMENT
return UriUtils.encodeReserved(value.toString(), type, Util.UTF_8);
}
@Override
String expand(Object variable, boolean encode) {
StringBuilder expanded = new StringBuilder();
expanded.append((encode) ? encode(variable) : variable);
String result = expanded.toString();
return result;
}
}
}
public class UriUtils {
public static String encodeReserved(String value, FragmentType type, Charset charset) {
return encodeChunk(value, type, charset);
}
private static String encodeChunk(String value, FragmentType type, Charset charset) {
byte[] data = value.getBytes(charset);
ByteArrayOutputStream encoded = new ByteArrayOutputStream();
for (byte b : data) {
if (type.isAllowed(b)) {
// 3.1 如果不需要转义,则不进行转义操作
encoded.write(b);
} else {
/* percent encode the byte */
// 3.2 否则,进行编码
pctEncode(b, encoded);
}
}
return new String(encoded.toByteArray());
}
enum FragmentType {
URI {
@Override
boolean isAllowed(int c) {
return isUnreserved(c);
}
},
PATH_SEGMENT {
@Override
boolean isAllowed(int c) {
return this.isPchar(c) || (c == '/');
}
}
abstract boolean isAllowed(int c);
protected boolean isAlpha(int c) {
return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
}
protected boolean isDigit(int c) {
return (c >= '0' && c <= '9');
}
protected boolean isSubDelimiter(int c) {
return (c == '!') || (c == '$') || (c == '&') || (c == '\'') || (c == '(') || (c == ')')
|| (c == '*') || (c == '+') || (c == ',') || (c == ';') || (c == '=');
}
protected boolean isUnreserved(int c) {
return this.isAlpha(c) || this.isDigit(c) || c == '-' || c == '.' || c == '_' || c == '~';
}
protected boolean isPchar(int c) {
return this.isUnreserved(c) || this.isSubDelimiter(c) || c == ':' || c == '@';
}
}
}
从源码上可以看出,&
字符属于 isSubDelimiter()
,所以不会被转义。
测试
package feign.template;
import feign.Util;
public class UriUtilsDemo {
public static void main(String[] args) {
String str = "aa&aa";
// 输出:aa&aa
System.out.println(UriUtils.encodeReserved(str, UriUtils.FragmentType.PATH_SEGMENT, Util.UTF_8));
// 输出:aa%26aa
System.out.println(UriUtils.encodeReserved(str, UriUtils.FragmentType.URI, Util.UTF_8));
}
}
解决方案:
- (一)升级
feign-core
版本,feign-core-10.12
已经没有这个问题。 - (二)使用
@RequestBody
替换@RequestParam
。
网友评论