使用spring-mvc
注解:
- 如何定义一个可以进行
POST form-url-encoded
的@FeignClient
?
使用spring-mvc
注解:
POST form-url-encoded
的@FeignClient
?使用 FormEncoder 来处理 Feign 请求:
你的 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)
}
具有 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>
Decoder
配置@Bean
,例如return new GsonDecoder();
。 - Neeraj Singh@Bean Gson upbeatGson() { return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create();}
- 因此我才提到。否则,如果JSONDecoder - 默认版本可以工作,那就没有必要了。 - Neeraj Singh@FeignClient(configuration = Client.Configuration.class)
才能使其工作。答案应该被编辑。 - thchp仅为补充已接受的答案,我们还可以使用POJO而不是Map<String, ?>
来传递表单参数给Feign客户端:
@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 */
}
这将导致请求的主体看起来像这样:
author_id=42&message=somemessage&ids[]=1&ids[]=2
@FormProperty
注解允许设置自定义字段名称;请注意,POJO 的静态或 final 字段以及继承的字段将不会作为表单内容序列化。
Kotlin 版本:
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>
)
@FormProperty
确实是我在寻找的!+1 - Yves Calaci@FormProperty
而不是@FeignProperty
,但我无法编辑它。 - august0490额外补充一点... 可以使用Spring抽象类org.springframework.util.MultiValueMap
,该类没有其他依赖项(只需spring-cloud-starter-openfeign)。
@PostMapping(value = "/your/path/here",
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
YourDtoResponse formUrlEncodedEndpoint(MultiValueMap<String, Object> params);
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("param1", "Value 1");
params.add("param2", 2);
在 Kotlin 中测试: 对我有效的方法如下:
@Configuration
class FeignFormConfiguration {
@Bean
fun multipartFormEncoder(): Encoder {
return SpringFormEncoder(SpringEncoder {
HttpMessageConverters(
RestTemplate().messageConverters
)
})
}
}
@FeignClient(
value = "client",
url = "localhost:9091",
configuration = [FeignFormConfiguration::class]
)
interface CoreClient {
@RequestMapping(
method = [RequestMethod.POST],
value = ["/"],
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = ["application/json"]
)
fun callback(@RequestBody form: Map<String, *>): AnyDTO?
}
// ----- other code --------
@Autowired
private lateinit var coreClient: CoreClient
fun methodName() {
coreClient.callback(form)
}
// ----- other code --------
@FeignClient(name = "${feign.repository.name}", url = "${feign.repository.url}")
public interface LoginRepository {
@PostMapping(value = "${feign.repository.endpoint}", consumes = APPLICATION_FORM_URLENCODED_VALUE)
LoginResponse signIn(@RequestBody Map<String, ?> form);
}
表单是Map<String, Object> loginCredentials = new HashMap<>();
在Feign编码器中,如果要使用url-form-encoded数据进行POST请求,则必须使用FormEncoder
。
将依赖项包含到您的应用程序中:
Maven:
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
SomeFeign sample = Feign.builder()
.encoder(new FormEncoder(new JacksonEncoder()))
.target(SomeFeign.class, "http://sample.test.org");
@RequestLine("POST /submit/form")
@Headers("Content-Type: application/x-www-form-urlencoded")
void from (@Param("field1") String field1, @Param("field2") String field2);
对于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);
public class CoreFeignConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
@Primary
@Scope("prototype")
Encoder feignFormEncoder() {
return new FormEncoder(new SpringEncoder(this.messageConverters));
}
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
Logger logger() {
return new MyLogger();
}
private static class MyLogger extends Logger {
@Override
protected void log(String s, String s1, Object... objects) {
System.out.println(String.format(s + s1, objects)); // Change me!
}
}
}
在接口中 @FeignClient(name = "resource-service1", url = "NOT_USED", configuration = CoreFeignConfiguration.class)
public interface TestFc {
@RequestMapping( method=RequestMethod.POST,consumes = "application/x-www-form-urlencoded")
//@Headers("Content-Type: application/x-www-form-urlencoded")
ResponseEntity<String> test(URI baseUrl,
Map<String,?> request);
}
Map<String, ?> formParams
,问号是必须的。 - Max Peng