美文网首页
Feign @RequestParams & 符号未转义

Feign @RequestParams & 符号未转义

作者: 蓝笔头 | 来源:发表于2021-07-28 15:58 被阅读0次

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

参考

相关文章

网友评论

      本文标题:Feign @RequestParams & 符号未转义

      本文链接:https://www.haomeiwen.com/subject/jrmzmltx.html