feign errordecoder,feign自定义编码器

  feign errordecoder,feign自定义编码器

  

目录

假装调用中文参数被编码编译原因记录今天遇到的假装多参数问题1.邮政方式2.得到方式

 

  

Feign调用中文参数被encode编译

 

  

原因

在实现一个假装调用时使用了邮政请求,并且拼接全球资源定位器(统一资源定位器)参数,名称传值为中文时被编码转译,且最终接取数据之前未被译转译回,问题探索:

 

  feign:

  @ FeignClient(name= service-test )公共接口TestServiceApi { @ post映射(/test/ABC )公共字符串getTestNo(@RequestParam(code )字符串代码,@RequestParam(name )字符串名称);}controller:

  @RequestMapping(/test )公共接口测试控制器{ @ auto wired private TestService TestService;@ post mapping(/ABC )public String getTestNo(@ request param( code )String code,@ request param( name )String name){ return testservice。查询(代码,名称);} }在控制器中接到的中文参数被URIEncode转译了

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

  找到假装的入口类反射假装中拼装请求模板的方法:

  @ Override公共请求模板create(Object[]argv){ request template mutable=new request template(metadata。template());if (metadata.urlIndex()!=null){ int URL index=元数据。URL索引();checkArgument(argv[urlIndex]!=null,“URI参数%s为null”,URL索引);mutable.insert(0,字符串。(argv[URL索引])的值;} MapString,Object var builder=new LinkedHashMapString,Object();for (EntryInteger,集合字符串条目:元数据。indexto name().entry set()){ int I=entry。getkey();对象值=argv[entry。getkey()];如果(值!=null) { //空值被跳过10 . if(indextoexpander。包含键(I)){ value=expandElements(indextoexpander。get(I),value);} for(字符串名称:条目。getvalue()){ var builder。put(名称,值);} } } //组装模板的方法请求模板template=resolve(argv,mutable,var builder);if (metadata.queryMapIndex()!=null) { //在初始解析后添加查询映射参数,以便它们//优先于任何预定义的值template=addQueryMapQueryP

  arameters(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);

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

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: