【问题标题】:How to POST form-url-encoded data with Spring Cloud Feign如何使用 Spring Cloud Feign 发布表单 URL 编码的数据
【发布时间】:2016-06-18 14:29:42
【问题描述】:

使用spring-mvc注解:

  • 如何定义一个@FeignClient 可以POST form-url-encoded

【问题讨论】:

    标签: spring-mvc spring-cloud spring-cloud-feign feign


    【解决方案1】:

    对 Feign 使用 FormEncoder

    你的 Feign 配置可能如下所示:

    class CoreFeignConfiguration {
      @Autowired
      private ObjectFactory<HttpMessageConverters> messageConverters
    
      @Bean
      @Primary
      @Scope(SCOPE_PROTOTYPE)
      Encoder feignFormEncoder() {
          new FormEncoder(new SpringEncoder(this.messageConverters))
      }
    }
    

    然后,客户端可以这样映射:

    @FeignClient(name = 'client', url = 'localhost:9080', path ='/rest',
        configuration = CoreFeignConfiguration)
    interface CoreClient {
        @RequestMapping(value = '/business', method = POST, 
                     consumes = MediaType.APPLICATION_FORM_URLENCODED)
        @Headers('Content-Type: application/x-www-form-urlencoded')
        void activate(Map<String, ?> formParams)
    }
    

    【讨论】:

    • 注意这一行Map&lt;String, ?&gt; formParams,问号是必填项。
    • 对于那些不认识 groovy 的人 - 这是在 groovy 中,因此不是“return”,“;”等:)
    • 不是很有用,它要求我的 pojo 有 @FormProperty 但不检查超类,我不能在客户端调用中单独提供 20 个表单属性。
    • 你不需要额外的 headers 注释,feign 自动将其放置在消耗配置中。
    【解决方案2】:

    带有简化版 kazuar 解决方案的完整 Java 代码,可与 Spring Boot 配合使用:

    import java.util.Map;
    import feign.codec.Encoder;
    import feign.form.spring.SpringFormEncoder;
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.cloud.openfeign.support.SpringEncoder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
    
    @FeignClient(name = "srv", url = "http://s.com")
    public interface Client {
    
        @PostMapping(value = "/form", consumes = APPLICATION_FORM_URLENCODED_VALUE)
        void login(@RequestBody Map<String, ?> form);
    
        class Configuration {
            @Bean
            Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> converters) {
                return new SpringFormEncoder(new SpringEncoder(converters));
            }
        }
    }
    

    依赖:

    <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

    【讨论】:

    • 可能无关但值得一提。如果您期待 JSON 响应。您可能需要为Decoder 配置@Bean return new GsonDecoder();
    • 不,spring boot中已经配置了Jackson解码器。
    • 是的,没错。默认的 JSONDecoder 已经配置好了。但是,我已启用 gson 作为默认转换器并使用自定义版本 @Bean Gson upbeatGson() { return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create();} - 因此我提到了。否则,如果 JSONDecoder - 默认版本有效,则不需要。
    • 在您的 @FeignClient 注释中只是错过了 configuration = yourClass.Configuration.class
    • 正如@HenriqueSchmitt 所说,我必须设置@FeignClient(configuration = Client.Configuration.class) 才能使其工作。答案应该被编辑
    【解决方案3】:

    对于 POST 中的 url-form-encoded 数据,您必须在 Feign 编码器中使用 FormEncoder

    将依赖项添加到您的应用中:

    马文:

    <dependency>
      <groupId>io.github.openfeign.form</groupId>
      <artifactId>feign-form</artifactId>
      <version>3.8.0</version>
    </dependency>
    

    像这样将 FormEncoder 添加到 Feign.Builder 中:

    SomeFeign sample  = Feign.builder()
                          .encoder(new FormEncoder(new JacksonEncoder()))
                          .target(SomeFeign.class, "http://sample.test.org");
    

    在 Feign 界面中

    @RequestLine("POST /submit/form")
    @Headers("Content-Type: application/x-www-form-urlencoded")
    void from (@Param("field1") String field1, @Param("field2") String field2);
    

    更多信息请参考: https://github.com/OpenFeign/feign-form

    【讨论】:

    • 此方法会导致“Java.lang.NoSuchMethodError”。
    【解决方案4】:

    为了补充accepted answer,也可以使用POJO代替Map&lt;String, ?&gt;来传递表单参数给feign客户端:

    @FeignClient(configuration = CustomConfig.class)
    interface Client {
    
        @PostMapping(
            path = "/some/path", 
            consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
        void postComment(CommentFormDto formDto);
        ...
    }
    ...
    
    class CustomConfig {
        @Bean
        Encoder formEncoder() {
            return new feign.form.FormEncoder();
        }
    }
    ...
    
    class CommentFormDto {
    
        private static String willNotBeSerialized;
    
        private final Integer alsoWillNotBeSerialized;
    
        @feign.form.FormProperty("author_id")
        private Long authorId;
    
        private String message;
    
        @feign.form.FormProperty("ids[]")
        private List<Long> ids;
        
        /* getters and setters omitted for brevity */  
    }
    

    这将导致请求的正文如下所示:

    author_id=42&message=somemessage&ids[]=1&ids[]=2
    

    @FeignProperty注解允许设置自定义字段名称;请注意 POJO 的 static 或 final 字段以及继承的字段,不会被序列化为表单内容。

    【讨论】:

      【解决方案5】:

      对于 Feign.Builder,我的工作没有 JacksonEncoder,只有 Feign FormEncoder:

      将 FormEncoder 添加到您的 Feign.Builder:

      SomeFeign sample  = Feign.builder()
                        .encoder(new FormEncoder())     <==difference here
                        .target(SomeFeign.class, "http://sample.test.org");
      

      我在 pom.xml 中添加的 feign 依赖:

      <dependency>
              <groupId>io.github.openfeign</groupId>
              <artifactId>feign-core</artifactId>
              <version>11.8</version>
          </dependency>
      
          <dependency>
              <groupId>io.github.openfeign</groupId>
              <artifactId>feign-jackson</artifactId>
              <version>11.8</version>
          </dependency>
          
          <dependency>
              <groupId>io.github.openfeign.form</groupId>
              <artifactId>feign-form</artifactId>
              <version>3.8.0</version>
          </dependency>
      

      pom.xml 中的父级是:

      <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.6.2</version>
          <relativePath/> <!-- lookup parent from repository -->
      </parent>
      

      Ramanan 给出的 feign 界面:

      @RequestLine("POST /submit/form")
      @Headers("Content-Type: application/x-www-form-urlencoded")
      void from (@Param("field1") String field1, @Param("field2") String field2);
      

      【讨论】:

        猜你喜欢
        • 2021-07-21
        • 1970-01-01
        • 2015-06-08
        • 2017-07-14
        • 2016-11-17
        • 2015-08-24
        • 1970-01-01
        • 2017-01-20
        • 1970-01-01
        相关资源
        最近更新 更多