美文网首页spring cloud
Spring Cloud Feign使用ApacheHttpCl

Spring Cloud Feign使用ApacheHttpCl

作者: Carlyle1993 | 来源:发表于2018-02-02 13:25 被阅读1581次

    类似GET请求的方式,指定method为POST

    @FeignClient(name = "${serviceName}")
    public interface HotService
    {
        @RequestMapping(value = "/term/hot", method = RequestMethod.POST)
        public Map<String, Object> hot(String terms);
    }
    

    请求报错:java.lang.IllegalArgumentException: MIME type may not contain reserved characters
    找到这段异常信息所在位置
    org.apache.http.entity.ContentType

        public static ContentType create(final String mimeType, final Charset charset) {
            final String type = Args.notBlank(mimeType, "MIME type").toLowerCase(Locale.ROOT);
            Args.check(valid(type), "MIME type may not contain reserved characters");
            return new ContentType(type, charset);
        }
    
        private static boolean valid(final String s) {
            for (int i = 0; i < s.length(); i++) {
                final char ch = s.charAt(i);
                if (ch == '"' || ch == ',' || ch == ';') {
                    return false;
                }
            }
            return true;
        }
    

    可以看出来是检测Content-Type不合法报的异常,但在代码中我们并没有指定Content-Type,所以应该是使用了默认值。
    feign.httpclient.ApacheHttpClient

        private ContentType getContentType(Request request) {
            ContentType contentType = ContentType.DEFAULT_TEXT;
            Iterator var3 = request.headers().entrySet().iterator();
    
            while(var3.hasNext()) {
                Entry<String, Collection<String>> entry = (Entry)var3.next();
                if(((String)entry.getKey()).equalsIgnoreCase("Content-Type")) {
                    Collection values = (Collection)entry.getValue();
                    if(values != null && !values.isEmpty()) {
                        contentType = ContentType.create((String)((Collection)entry.getValue()).iterator().next(), request.charset());
                        break;
                    }
                }
            }
    
            return contentType;
        }
    

    在ApacheHttpClient中看到默认设置的Content-Type是ContentType.DEFAULT_TEXT,即text/plain; charset=ISO-8859-1,其中包含分号,也就导致了上面提到的异常。所以POST请求时我们需要指定Content-Type,修改下代码:

    @FeignClient(name = "${serviceName}")
    public interface HotService
    {    
        @RequestMapping(value = "/term/hot", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
        public Map<String, Object> hot(String terms);
    }
    

    通过给@RequestMapping设置consumes参数,我们指定提交内容类型为表单数据。
    再次请求,请求成功发出,但是在服务端接受参数时,对应的值是null,这里我们考虑开启Feign日志,查看传递的参数是什么。

    新建一个类
    @Configuration
    public class FeignConfiguration
    {
        @Bean
        public Logger.Level feignLoggerLevel() {
            return feign.Logger.Level.FULL;
        }
    }
    在原先的@FeignClient注解中添加参数configuration,变成
    @FeignClient(name = "${serviceName}", configuration = FeignConfiguration.class)
    同时指定service类的日志级别为DEBUG:
    logging.level.com.cs.search.service.HotService: DEBUG
    

    请求之后看到下面的日志:



    可以看到请求确实把值传递出去了,但是却不是以“键=值”的形式,只有“值”,所以服务端在获取指定参数时值就是null。看来service中请求时并不是如我们所想的那样把值绑定到了方法的参数上去,顺着这个想下去,既然请求时直接把值传递出去了,那如果我们的传递的值本身就是“键=值”这样的形式呢?

    我们把原先的请求方式
    hotService.hot(terms)
    替换成
    hotService.hot("terms="+terms);
    

    这次请求之后,Feign的日志如下:



    变成了我们预想的样子,当然服务端也正确的接受了。
    但是,这种方法相当于手动构建body内容,某种意义上相当于是个GET请求,有没有更好的解决方法?考虑到现在问题的关键在于,我们传了一个String类型的参数,系统似乎没有使用正确的HttpMessageConverters来构建请求参数。Spring中有一个类型是MultiValueMap,这种类型的参数,Spring会将其解析成application/x-www-form-urlencoded,因此我们将参数替换成这种类型尝试一下。

    @FeignClient(name = "${serviceName}")
    public interface HotService
    {
        @RequestMapping(value = "/term/hot", method = RequestMethod.POST)
        public Map<String, Object> hot(MultiValueMap params);
    }
    注意到上面提到的consumes参数去掉了,用了MultiValueMap就没必要再设置了
    相应的,调用方式也要改变:
    LinkedMultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
    multiValueMap.add("terms", terms);
    Map<String, Object> result = hotService.hot(multiValueMap);
    

    经过测试,完美解决问题。

    相关文章

      网友评论

        本文标题:Spring Cloud Feign使用ApacheHttpCl

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