FeignClient 与 Hateoas PagedModel:内容始终为空
我有一个产生 Hateoas 的端点:
@GetMapping()
public ResponseEntity<PagedModel<ContentModel>> getContent(
@RequestParam(required = false) final String sortBy,
@RequestParam(defaultValue = "0") final Integer page,
@RequestParam(defaultValue = "0") final Integer size) {
// .. do stuff
}
如果我使用 RestTemplate 调用此端点,我会得到预期的结果。 但是如果我使用 FeignClient
:
@FeignClient(url = "${project.backend.url}/contents")
public interface ContentClient {
@GetMapping
ResponseEntity<PagedModel<ContentModel>> getContent(
@RequestParam(required = false, name = "sortBy") final String sortBy,
@RequestParam(defaultValue = "0", name = "page") final Integer page,
@RequestParam(defaultValue = "0", name = "size") final Integer size);
}
我仍然得到元数据正确但内容为空的响应:
backend-services-test_1 | 2022-03-15 11:43:29.713 INFO 80 --- [ main] d.b.b.p.p.s.c.CommonQueriesAndAsserts : body: PagedResource { content: [], metadata: Metadata { number: 0, total pages: 1, total elements: 9, size: 2147483647 }, links: }
我尝试添加:@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)< /代码> 但这并没有解决问题。
此外,这并没有解决问题: 在客户端服务中与 Feign 客户端一起使用时,Spring Data Rest Hateoas 资源对象为空
我也有此配置来支持带有 HAL 的 jackson:
@Configuration
public class ServiceConfiguration {
@Bean
public ObjectMapper objectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new Jackson2HalModule());
return objectMapper;
}
@Bean
public MappingJackson2HttpMessageConverter converter() {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(singletonList(HAL_JSON));
converter.setObjectMapper(objectMapper());
return converter;
}
@Bean
public TestRestTemplate testRestTemplate(final RestTemplateBuilder builder) {
return new TestRestTemplate(builder.messageConverters(converter()));
}
}
我需要做什么,以便 FeignClient 可以解析它获取的信息?
EIDT
我启用了 DEBUG 和 Feign FULL 日志记录,可以看到 json 数据是正确的:
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] <--- HTTP/1.1 200 (607ms)
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] cache-control: no-cache, no-store, max-age=0, must-revalidate
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] connection: keep-alive
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] content-type: application/json
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] date: Tue, 15 Mar 2022 12:24:54 GMT
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] expires: 0
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] keep-alive: timeout=60
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] pragma: no-cache
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] transfer-encoding: chunked
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] x-content-type-options: nosniff
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] x-frame-options: DENY
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] x-xss-protection: 1; mode=block
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent]
backend-services-test_1 | 2022-03-15 13:24:54.967 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] {
backend-services-test_1 | "links" : [ {
backend-services-test_1 | "rel" : "self",
backend-services-test_1 | "href" : "http://backend-services:8082/contents?sortBy&page=0&size=2000"
backend-services-test_1 | } ],
backend-services-test_1 | "content" : [ {
backend-services-test_1 | "key" : {
backend-services-test_1 | "id" : 1,
backend-services-test_1 | "version" : "2.0"
backend-services-test_1 | },
backend-services-test_1 | "type" : "CONTENT",
backend-services-test_1 | "title" : "Title",
backend-services-test_1 | "subtitle" : "Subtitle",
backend-services-test_1 | }, {
backend-services-test_1 | "key" : {
backend-services-test_1 | "id" : 2,
backend-services-test_1 | "version" : "2.0"
backend-services-test_1 | },
backend-services-test_1 | "type" : "CONTENT",
backend-services-test_1 | "title" : "Title",
backend-services-test_1 | "subtitle" : "Subtitle",
...
backend-services-test_1 | } ],
backend-services-test_1 | "page" : {
backend-services-test_1 | "size" : 2147483647,
backend-services-test_1 | "totalElements" : 9,
backend-services-test_1 | "totalPages" : 1,
backend-services-test_1 | "number" : 0
backend-services-test_1 | }
backend-services-test_1 | }
EIDT 2
添加:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>9.3.1</version>
</dependency>
和:
@Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new JacksonDecoder(objectMapper()));
}
也没有解决问题。
I have an endpoint which produces Hateoas:
@GetMapping()
public ResponseEntity<PagedModel<ContentModel>> getContent(
@RequestParam(required = false) final String sortBy,
@RequestParam(defaultValue = "0") final Integer page,
@RequestParam(defaultValue = "0") final Integer size) {
// .. do stuff
}
If I use RestTemplate
to call this endpoint I get the expected result.
But If I use a FeignClient
:
@FeignClient(url = "${project.backend.url}/contents")
public interface ContentClient {
@GetMapping
ResponseEntity<PagedModel<ContentModel>> getContent(
@RequestParam(required = false, name = "sortBy") final String sortBy,
@RequestParam(defaultValue = "0", name = "page") final Integer page,
@RequestParam(defaultValue = "0", name = "size") final Integer size);
}
I still get a response where the metadata is correct but the content is empty:
backend-services-test_1 | 2022-03-15 11:43:29.713 INFO 80 --- [ main] d.b.b.p.p.s.c.CommonQueriesAndAsserts : body: PagedResource { content: [], metadata: Metadata { number: 0, total pages: 1, total elements: 9, size: 2147483647 }, links: }
I tried to add: @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
but that did not solve the problem.
Also this did not solve the problem: Spring Data Rest Hateoas Resources object empty when consuming with Feign client in client service
I also have this config to support jackson with HAL:
@Configuration
public class ServiceConfiguration {
@Bean
public ObjectMapper objectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new Jackson2HalModule());
return objectMapper;
}
@Bean
public MappingJackson2HttpMessageConverter converter() {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(singletonList(HAL_JSON));
converter.setObjectMapper(objectMapper());
return converter;
}
@Bean
public TestRestTemplate testRestTemplate(final RestTemplateBuilder builder) {
return new TestRestTemplate(builder.messageConverters(converter()));
}
}
What do I need to do so that FeignClient can parse the information it gets?
EIDT
I enabled DEBUG and Feign FULL logging and I can see that the json data is correct:
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] <--- HTTP/1.1 200 (607ms)
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] cache-control: no-cache, no-store, max-age=0, must-revalidate
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] connection: keep-alive
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] content-type: application/json
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] date: Tue, 15 Mar 2022 12:24:54 GMT
backend-services-test_1 | 2022-03-15 13:24:54.947 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] expires: 0
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] keep-alive: timeout=60
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] pragma: no-cache
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] transfer-encoding: chunked
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] x-content-type-options: nosniff
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] x-frame-options: DENY
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] x-xss-protection: 1; mode=block
backend-services-test_1 | 2022-03-15 13:24:54.948 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent]
backend-services-test_1 | 2022-03-15 13:24:54.967 DEBUG 81 --- [ main] d.b.b.p.p.steps.content.ContentClient : [ContentClient#getContent] {
backend-services-test_1 | "links" : [ {
backend-services-test_1 | "rel" : "self",
backend-services-test_1 | "href" : "http://backend-services:8082/contents?sortBy&page=0&size=2000"
backend-services-test_1 | } ],
backend-services-test_1 | "content" : [ {
backend-services-test_1 | "key" : {
backend-services-test_1 | "id" : 1,
backend-services-test_1 | "version" : "2.0"
backend-services-test_1 | },
backend-services-test_1 | "type" : "CONTENT",
backend-services-test_1 | "title" : "Title",
backend-services-test_1 | "subtitle" : "Subtitle",
backend-services-test_1 | }, {
backend-services-test_1 | "key" : {
backend-services-test_1 | "id" : 2,
backend-services-test_1 | "version" : "2.0"
backend-services-test_1 | },
backend-services-test_1 | "type" : "CONTENT",
backend-services-test_1 | "title" : "Title",
backend-services-test_1 | "subtitle" : "Subtitle",
...
backend-services-test_1 | } ],
backend-services-test_1 | "page" : {
backend-services-test_1 | "size" : 2147483647,
backend-services-test_1 | "totalElements" : 9,
backend-services-test_1 | "totalPages" : 1,
backend-services-test_1 | "number" : 0
backend-services-test_1 | }
backend-services-test_1 | }
EIDT 2
Adding:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>9.3.1</version>
</dependency>
and:
@Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new JacksonDecoder(objectMapper()));
}
Also did not solve the problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因此,使用自定义 feign 解码器,我走上了正确的道路。
这是使它工作的完整配置:
So with the custom feign decoder I was on the right path.
Here the full config which made it working: