feign调用中文参数被encode编译的问题

目录
  • Feign调用中文参数被encode编译
    • 原因
  • 记录今天遇到的feign多参数问题
    • 1.Post方式
    • 2.Get方式

Feign调用中文参数被encode编译

原因

在实现一个feign调用时使用了Post请求,并且拼接url参数,name传值为中文时被encode转译,且最终接取数据之前未被decode转译回,问题探索:

feign:

@FeignClient(name = "service-test")
public interface TestServiceApi {
    @PostMapping("/test/abc")
    public String getTestNo(@RequestParam("code") String code, @RequestParam("name") String name);
}

controller:

@RequestMapping("/test")
public interface TestController {
    @Autowired
    private TestService testService;
    @PostMapping("/abc")
    public String getTestNo(@RequestParam("code") String code, @RequestParam("name") String name) {
        return testService.query(code, name); 
    }    
}

在controller中接到的中文参数被URIEncode转译了

测试 被转译成:%E6%B5%8B%E8%AF%95

找到feign的入口类ReflectiveFeign中拼装RequestTemplate的方法:

    @Override
    public RequestTemplate create(Object[] argv) {
      RequestTemplate mutable = new RequestTemplate(metadata.template());
      if (metadata.urlIndex() != null) {
        int urlIndex = metadata.urlIndex();
        checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
        mutable.insert(0, String.valueOf(argv[urlIndex]));
      }
      Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();
      for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {
        int i = entry.getKey();
        Object value = argv[entry.getKey()];
        if (value != null) { // Null values are skipped.
          if (indexToExpander.containsKey(i)) {
            value = expandElements(indexToExpander.get(i), value);
          }
          for (String name : entry.getValue()) {
            varBuilder.put(name, value);
          }
        }
      }
      // 组装template的方法
      RequestTemplate template = resolve(argv, mutable, varBuilder);
      if (metadata.queryMapIndex() != null) {
        // add query map parameters after initial resolve so that they take
        // precedence over any predefined values
        template = addQueryMapQueryParameters(argv, template);
      }
      if (metadata.headerMapIndex() != null) {
        template = addHeaderMapHeaders(argv, template);
      }
      return template;
    }

在RequestTemplate类中如果是拼接在url后的param那么会被使用encodeValueIfNotEncoded都encode转译,但是不会走decode的方法

 /**
   * Resolves any template parameters in the requests path, query, or headers against the supplied
   * unencoded arguments. <br> <br><br><b>relationship to JAXRS 2.0</b><br> <br> This call is
   * similar to {@code javax.ws.rs.client.WebTarget.resolveTemplates(templateValues, true)} , except
   * that the template values apply to any part of the request, not just the URL
   */
  RequestTemplate resolve(Map<String, ?> unencoded, Map<String, Boolean> alreadyEncoded) {
    replaceQueryValues(unencoded, alreadyEncoded);
    Map<String, String> encoded = new LinkedHashMap<String, String>();
    for (Entry<String, ?> entry : unencoded.entrySet()) {
      final String key = entry.getKey();
      final Object objectValue = entry.getValue();
      String encodedValue = encodeValueIfNotEncoded(key, objectValue, alreadyEncoded);
      encoded.put(key, encodedValue);
    }
    String resolvedUrl = expand(url.toString(), encoded).replace("+", "%20");
    if (decodeSlash) {
      resolvedUrl = resolvedUrl.replace("%2F", "/");
    }
    url = new StringBuilder(resolvedUrl);
    Map<String, Collection<String>> resolvedHeaders = new LinkedHashMap<String, Collection<String>>();
    for (String field : headers.keySet()) {
      Collection<String> resolvedValues = new ArrayList<String>();
      for (String value : valuesOrEmpty(headers, field)) {
        String resolved = expand(value, unencoded);
        resolvedValues.add(resolved);
      }
      resolvedHeaders.put(field, resolvedValues);
    }
    headers.clear();
    headers.putAll(resolvedHeaders);
    if (bodyTemplate != null) {
      body(urlDecode(expand(bodyTemplate, encoded)));
    }
    return this;
  }

如果传入的值在requestBody中,则不会被encode转译

    @Override
    public void encode(Object requestBody, Type bodyType, RequestTemplate request)
            throws EncodeException {
        // template.body(conversionService.convert(object, String.class));
        if (requestBody != null) {
            Class<?> requestType = requestBody.getClass();
            Collection<String> contentTypes = request.headers().get("Content-Type");
            MediaType requestContentType = null;
            if (contentTypes != null && !contentTypes.isEmpty()) {
                String type = contentTypes.iterator().next();
                requestContentType = MediaType.valueOf(type);
            }
            for (HttpMessageConverter<?> messageConverter : this.messageConverters
                    .getObject().getConverters()) {
                if (messageConverter.canWrite(requestType, requestContentType)) {
                    if (log.isDebugEnabled()) {
                        if (requestContentType != null) {
                            log.debug("Writing [" + requestBody + "] as \""
                                    + requestContentType + "\" using ["
                                    + messageConverter + "]");
                        }
                        else {
                            log.debug("Writing [" + requestBody + "] using ["
                                    + messageConverter + "]");
                        }
                    }
                    FeignOutputMessage outputMessage = new FeignOutputMessage(request);
                    try {
                        @SuppressWarnings("unchecked")
                        HttpMessageConverter<Object> copy = (HttpMessageConverter<Object>) messageConverter;
                        copy.write(requestBody, requestContentType, outputMessage);
                    }
                    catch (IOException ex) {
                        throw new EncodeException("Error converting request body", ex);
                    }
                    // clear headers
                    request.headers(null);
                    // converters can modify headers, so update the request
                    // with the modified headers
                    request.headers(getHeaders(outputMessage.getHeaders()));
                    // do not use charset for binary data
                    if (messageConverter instanceof ByteArrayHttpMessageConverter) {
                        request.body(outputMessage.getOutputStream().toByteArray(), null);
                    } else {
                        request.body(outputMessage.getOutputStream().toByteArray(), Charset.forName("UTF-8"));
                    }
                    return;
                }
            }
            String message = "Could not write request: no suitable HttpMessageConverter "
                    + "found for request type [" + requestType.getName() + "]";
            if (requestContentType != null) {
                message += " and content type [" + requestContentType + "]";
            }
            throw new EncodeException(message);
        }
    }

综合上述的调试,如果在Post中拼接参数那么会被encode转译,且不会被decode转译,如果使用body传参,那么不会出现转译问题,如果必须使用拼接传参,那么可以使用方法

1. @RequestLine的注解自定义参数的格式,具体参考该注解的使用方式。

2.在Feign的RequestInterceptor将传递的值decode的扩展方法。

记录今天遇到的feign多参数问题

1.Post方式

错误写法示例如下:

public int save(@RequestBody final User u, @RequestBody final School s);

错误原因:

fegin中可以有多个@RequestParam,但只能有不超过一个@RequestBody,@RequestBody用来修饰对象,但是既有@RequestBody也有@RequestParam,

那么参数就要放在请求的Url中,@RequestBody修饰的就要放在提交对象中。

注意!!! 用来处理@RequestBody Content-Type 为 application/json,application/xml编码的内容

正确写法示例如下:

public int save(@RequestBody final Person p,@RequestParam("userId") String userId,@RequestParam("userTel") String userTel);

2.Get方式

错误写法示例如下:

@RequestMapping(value="/test", method=RequestMethod.GET)  
Model test(final String name,  final int age); 

错误原因:

异常原因:当使用Feign时,如果发送的是get请求,那么需要在请求参数前加上@RequestParam注解修饰,Controller里面可以不加该注解修饰,@RequestParam可以修饰多个,@RequestParam是用来修饰参数,不能用来修饰整个对象。

注意:@RequestParam Content-Type 为 application/x-www-form-urlencoded 而这种是默认的

正确写法示例如下:

@GetMapping("/getSchoolDetail")
    public ResultMap getSchoolDetail(@RequestParam("kSchoolId") LongkSchoolId,
     @RequestParam("kSchoolYearId") Long kSchoolYearId);

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Cloud中关于Feign的常见问题总结

    一.FeignClient接口,不能使用@GettingMapping 之类的组合注解 代码示例: @FeignClient("microservice-provider-user") public interface UserFeignClient { @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET) public User findById(@PathVariable(&quo

  • feign实现传递参数的三种方式小结

    需要注意的一点是,feign好像是无法传递list集合类型的,但是你可以通过传递对象类型,然后在接收方再次将对象装在集合中达到集合传递的效果 传递方式一:传递的都是基本数据类型 restful风格参数,用@PathVariable写着走就行了 传递方式二:传递数组类型的参数 不使用restful风格,直接用@RequestParam声明参数之间的对应关系. 传递方式三:传递带有对象的参数 1.使用restful风格的参数要用@Pathvarible声明参数对应关系,@Pathvariable用于

  • 解决SpringCloud Feign传对象参数调用失败的问题

    SpringCloud Feign传对象参数调用失败 不支持GET请求方式 使用Apache HttpClient替换Feign原生httpclient @RequestBody接收json参数 bootstrap-local.yml feign: httpclient: enabled: true pom.xml <!-- 使用Apache HttpClient替换Feign原生httpclient --> <dependency> <groupId>com.netf

  • SpringCloud Feign参数问题及解决方法

    这篇文章主要介绍了SpringCloud Feign参数问题及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 今天遇到使用Feign调用微服务,传递参数时遇到几个问题 1.无参数 以GET方式请求 服务提供者 @RequestMapping("/hello") public String Hello(){ return "hello,provider"; } 服务消费者 @GetMapping("

  • feign调用中文参数被encode编译的问题

    目录 Feign调用中文参数被encode编译 原因 记录今天遇到的feign多参数问题 1.Post方式 2.Get方式 Feign调用中文参数被encode编译 原因 在实现一个feign调用时使用了Post请求,并且拼接url参数,name传值为中文时被encode转译,且最终接取数据之前未被decode转译回,问题探索: feign: @FeignClient(name = "service-test") public interface TestServiceApi {  

  • Feign远程调用Multipartfile参数处理

    目录 Feign远程调用Multipartfile参数 解决方案 Feign远程调用传参问题 Feign远程调用Multipartfile参数 今天在写业务代码的时候遇到的问题, 前端请求A服务,能正确把参数给到A服务<参数里面包括文件类型的 Multipartfile>,但是当A服务调用B服务时把文件参数丢过去,那边接收不到,并且会报Multipartfile 参数错误. 在网上找到了答案,特此记录一下: 解决方案 必须的 在你的fegin 服务接口暴露的地方新建一个配置类. package

  • springcloud使用feign调用服务时参数内容过大问题

    目录 feign调用服务时参数内容过大 场景 解决方法 feign消费时,如果传入参数过长 导致feign.FeignException: status 400 reading错误 解决办法 feign调用服务时参数内容过大 场景 前端参数传入到gateway后,gateway使用feign调用服务时,传入的参数内容过大(参数常见于富文本.或者其他附属信息过多)会导致传输不过去,虽然配置可以调节内容大小,但是最大的也有上限,所以特殊处理一道. 例如该类参数: 解决方法 可新增两个redis公共方

  • 关于使用rust调用c++静态库并编译nodejs包的问题

    目录 一.创建项目 二.Cargo.toml 三.package.json 四.代码分析 在项目上经常要用到身份证阅读器.护照阅读仪.指纹仪等各种品牌硬件,假如每套系统的都做集成开发那代码的维护成本将变得很高,为此采用rust来调用厂家提供的sdk c++开发包并封装成nodejs包,用fastify来开发成web api独立的服务形式.这样我们开发系统时只需调用web接口即可,跨平台又可共用,方便快捷,话不多说来看代码如何实现. 一.创建项目 安装rust后,打开vs新建一个工程目录,我们通过

  • prototype 中文参数乱码解决方案

    在使用portotype,调用ajax方法时出现乱码,此时,获取页面中加入 可以试试;: Page.Response.Charset = "gb2312"; 如果不奏效,有人提供另外解决方案: 复制代码 代码如下: request: function(url) { this.url = url; this.method = this.options.method; this.encoding = this.options.encoding; var params = this.opti

  • 微服务通过Feign调用进行密码安全认证操作

    微服务通过Feign调用进行密码安全认证 在项目中,微服务之间的通信也是通过Feign代理的HTTP客户端通信,为了保护我们的业务微服务不被其他非法未经允许的服务调用, 我们要进行访问授权配置! Feign是客户端配置,@FeignClient注解有个configuation属性,可以配置我们自定义的配置类,在此类中注入微服务认证拦截器 /** * 访问微服务需要密码 * @return */ @Bean public FeignBasicAuthRequestInterceptor reque

  • 关于feign对x-www-form-urlencode类型的encode和decode问题

    目录 对x-www-form-urlencode类型的encode和decode问题 问题场景 问题原因 可能的解决办法(没来得及尝试) 附:feign的调用栈 feignx-www-form-urlencoded类型请求 试了好多方式,最后用以下方式成功 对x-www-form-urlencode类型的encode和decode问题 记录一下开发过程中遇到的一个问题. 问题场景 使用feign调用另一服务b时,在feign-client包里跑单测能调用成功,在另一项目a引入该feign-cli

  • feign 调用第三方服务中部分特殊符号未转义问题

    目录 调用第三方部分特殊符号未转义 1.问题发现过程 2.解决办法 3.疑问 @RequestParams&符号未转义 feign-core版本 源码分析 测试 解决方案 调用第三方部分特殊符号未转义 开发过程中,发现+(加号)这个符号没有转义,导致再调用服务的时候把加号转义成空格了.导致后台获取到的数据会不正确. 1. 问题发现过程 feign 解析参数的时候,使用的标准是 RFC 3986,这个标准的加号是不需要被转义的.其具体的实现是 feign.template.UriUtils#enc

  • asp.net中url地址传送中文参数时的两种解决方案

    在Web.comfig中配置 是一样的: <globalization requestEncoding="gb2312" responseEncoding="gb2312"/> 页面Header部分也都有 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 真是奇怪, 只好用了笨办法: 写参数: 复制代码 代码如下

随机推荐