如何使用Spring Cloud Feign发布form-url编码的数据

New*_*bie 9 spring-mvc spring-cloud spring-cloud-feign feign

使用spring-mvc注释,如何定义可以POST form-url-encoded的@FeignClient?

Mar*_*szS 13

带有简化版 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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

依赖:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

  • 不,Spring Boot中已经配置了Jackson解码器。 (2认同)
  • 在你的@FeignClient注释中刚刚错过了configuration = yourClass.Configuration.class (2认同)
  • 正如 @HenriqueSchmitt 所说,我必须设置 `@FeignClient(configuration = Client.Configuration.class)` 才能正常工作。答案应该编辑一下 (2认同)

小智 11

只是为了补充已接受的答案,还可以使用 POJO 而不是Map<String, ?>将表单参数传递给假客户端:

@FeignClient(configuration = CustomConfig.class)
interface Client {

    @PostMapping(
        path = "/some/path", 
        consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    void postComment(CommentFormDto formDto);
    ...
}
...
@Configuration
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 */  
}
Run Code Online (Sandbox Code Playgroud)

这将导致请求的正文看起来像这样:

author_id=42&message=somemessage&ids[]=1&ids[]=2
Run Code Online (Sandbox Code Playgroud)

@FormProperty注释允许设置自定义字段名称;请注意,POJO 的静态或最终字段以及继承的字段不会被序列化为表单内容。

对于科特林:

import org.springframework.http.MediaType

@FeignClient(configuration = [CustomConfig::class])
interface Client {

    @PostMapping(
        path = "/some/path", 
        consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
    postComment(CommentFormDto formDto): responseDto
    ...
}
...
import feign.form.FormEncoder

@Configuration
class CustomConfig {
    @Bean
    fun formEncoder(): FormEncoder {
        return FormEncoder()
    }
}
...
import feign.form.FormProperty

data class CommentFormDto (

    @FormProperty("author_id")
    var authorId: Long

    @FormProperty("ids[]")
    var ids: List<Long>

)
Run Code Online (Sandbox Code Playgroud)

  • 答案几乎没有错误。它将是“@FormProperty”而不是“@FeignProperty”,但我无法编辑它。 (3认同)

kaz*_*uar 8

使用表格编码器为假设:https://github.com/OpenFeign/feign-form,你的假装配置可能如下所示:

class CoreFeignConfiguration {

  @Autowired
  private ObjectFactory<HttpMessageConverters> messageConverters

  @Bean
  @Primary
  @Scope(SCOPE_PROTOTYPE)
  Encoder feignFormEncoder() {
      new FormEncoder(new SpringEncoder(this.messageConverters))
  }
}
Run Code Online (Sandbox Code Playgroud)

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

@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)
}
Run Code Online (Sandbox Code Playgroud)

  • 注意这一行`Map <String,?> formParams`,问号是必需的. (2认同)