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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM