zoukankan      html  css  js  c++  java
  • Feign form 表单提交的坑

    1、背景

    两个月前,刚入职新公司,需要 新启 一个工程 SDK, 做 三方接口 的转发,供多个部门使用。

    三方的 接口 只能 接收 application/x-www-form-urlencoded ,不支持 json 参数

    然而,接受的参数 有 下划线格式 (wan_id),很多接口的参数都 > 5个。

    原本想想 SDK 做下 包装,把众多的参数都封装成对象,用 feign 调用。

    刚使用 Jackson 来进行转换,但因为 接受端 不是 json 的格式,所以 入参 不能进行 下划线的转换。

    因为只能接受 application/x-www-form-urlencoded。刚使用feign 就有点懵

    2、查方案

    查看 Encoder

    查了很多文档,想看看 是否能在 encoder 的地方进行实现。当然失败告终,本身就不怎么熟悉,就直接尝试修改encoder,跨度太大了,方向有点问题

    入参 使用 Map

    想 Map作为参数 的方式 很通用, 调试 居然不行(不够仔细看文档导致)。我使用了 Map<String,Object> requestMap (这就是问题!!!) 。 试来试去不成功,郁闷了。

    痛点是 参数 用下划线的 形式。用对象字段名 一样的话没有什么问题。

    想来想去不应该,Map 传参数这么常见的 ,怎么不生效? 怀疑人生。 选择 了看源码debug。

    ​ 原来在进行 Map 判断的时候,发现了问题:

    public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
      String contentTypeValue = getContentTypeValue(template.headers());
      val contentType = ContentType.of(contentTypeValue);
      if (!processors.containsKey(contentType)) {
        delegate.encode(object, bodyType, template);
        return;
      }
    
      Map<String, Object> data;
      if (MAP_STRING_WILDCARD.equals(bodyType)) { //这里 专门对 Map 做了判断
        data = (Map<String, Object>) object;
      } else if (isUserPojo(bodyType)) {// 对象转换
        data = toMap(object);
      } else {
        delegate.encode(object, bodyType, template);
        return;
      }
    
      val charset = getCharset(contentTypeValue);
      processors.get(contentType).process(template, charset, data);
    }
    
    /**   这里 对  Map 做了  限制,只有 Map<String, ?> 才会相等
     * Type literal for {@code Map<String, ?>}.
     */
    public static final Type MAP_STRING_WILDCARD =
        new Types.ParameterizedTypeImpl(null, Map.class, String.class,
            new Types.WildcardTypeImpl(new Type[] {Object.class}, new Type[0]));
    

    这就是 Map 传参 没生效的 根本原因!!!!!

    记录下 feign 使用的步骤

    1、添加 pom

    <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-jackson</artifactId>
                <version>${feign.version}</version>
            </dependency>
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-core</artifactId>
                <version>${feign.version}</version>
            </dependency>
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-okhttp</artifactId>
                <version>${feign.version}</version>
            </dependency>
    
            <dependency>
                <groupId>io.github.openfeign.form</groupId>
                <artifactId>feign-form</artifactId>
                <version>${feign-form.version}</version>
            </dependency>
    
            <dependency>
                <groupId>io.github.openfeign.form</groupId>
                <artifactId>feign-form-spring</artifactId>
                <version>${feign-form.version}</version>
            </dependency>
    

    2、接口实现:

    public interface XxxApiService {
    		@Headers({CONTENT_TYPE + ":" + APPLICATION_FORM, ACCEPT + ":" + APPLICATION_JSON})
        @RequestLine(METHOD_POST + " /hello/{name}")
        ResponseBase demo(@Param("msg") String msg, @Param("name") String name);
    }
    

    3、定义property 中配置的 url等变量 (因为没有用到 服务注册,配置都是 在 property中进行切换)

    @ConfigurationProperties(prefix = "xxx.api")
    public class XxxApiProperties {
    
        private String url;
    
        private String key;
        }
    

    4、构建 feign的代理bean:

    @Bean
        public XxxApiService xxxApiService(okhttp3.OkHttpClient httpClient, XxxApiKeyInterceptor xxxApiKeyInterceptor, XxxHeaderInterceptor xxxHeaderInterceptor,
                                           XxxApiProperties properties) {
            return Feign.builder().client(new OkHttpClient(httpClient)).encoder(new FormEncoder(new JacksonEncoder())).queryMapEncoder(
                    new BeanQueryMapEncoder()).decoder(new JacksonDecoder()).requestInterceptor(bmcApiKeyInterceptor).requestInterceptor(xxxHeaderInterceptor).target(
                    XxxApiService.class, properties.getUrl());
        }
    

    总结

    1、feign form 表单 提交,Map 作为参数,必须 Map<String,?>。在查询过程中,当然看了官方文档和别人的博客,但就忽略了关键的点,这是需要改正的
    2、现在的回顾,相对刚碰到问题时的记录,少了一些细节。需要多记录当时的一些 问题,及寻求方案的中间过程
    3、以前对 feign,open feign, spring cloud openfeign 傻傻分不清,现在有了一点头绪。

    引用 小马哥的 分享资料:

    REST框架 使用场 景 请求映射注解 请求参数
    Feign 客户端 声明 @RequestLine @Param
    Spring Cloud Open Feign 客户端 声明 @ReqeustMapping @RequestParam
    JAX-RS 客户端、服 务端 声明 @Path @*Param
    Spring Web MVC 服 务端 声明 @ReqeustMapping @RequestParam
  • 相关阅读:
    第七章 Net 5.0 快速开发框架 YC.Boilerplate -- 数据层ORM 设计
    第六章 Net 5.0 快速开发框架 YC.Boilerplate -- 代码生成和数据库表生成
    第五章 Net 5.0 快速开发框架 YC.Boilerplate -- 缓存模块
    第四章 Net 5.0 快速开发框架 YC.Boilerplate-- 动态WebApi
    第三章 Net 5.0 快速开发框架 YC.Boilerplate-- 多租户介绍
    第二章 Net 5.0 快速开发框架 YC.Boilerplate-- 快速入门
    第一章 Net 5.0 快速开发框架 YC.Boilerplate--框架介绍
    【雕爷学编程】Arduino动手做(90)---4X4矩阵薄膜键盘模块
    【雕爷学编程】Arduino动手做(89)---8位双向电平转换模块
    多端自动化运行:pc+android+ios+小程序 均可
  • 原文地址:https://www.cnblogs.com/idea-persistence/p/13470911.html
Copyright © 2011-2022 走看看