FeignClient 与 Hateoas PagedModel:内容始终为空

发布于 2025-01-14 03:46:15 字数 6935 浏览 1 评论 0原文

我有一个产生 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

抽个烟儿 2025-01-21 03:46:16

因此,使用自定义 feign 解码器,我走上了正确的道路。
这是使它工作的完整配置:

@Configuration
public class FeignConfiguration {

  @Bean
  Logger.Level feignLoggerLevel() {
    return Level.FULL;
  }

  @Bean
  public ObjectMapper objectMapper() {
    return new ObjectMapper()
        .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
        .registerModule(new Jackson2HalModule());
  }

  @Bean
  public MappingJackson2HttpMessageConverter converter() {
    final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

    converter.setSupportedMediaTypes(singletonList(HAL_JSON));
    converter.setObjectMapper(objectMapper());

    return converter;
  }

  @Bean
  public Decoder feignDecoder() {
    return new ResponseEntityDecoder(
        new SpringDecoder(
            () -> new HttpMessageConverters(converter())));
  }
}

So with the custom feign decoder I was on the right path.
Here the full config which made it working:

@Configuration
public class FeignConfiguration {

  @Bean
  Logger.Level feignLoggerLevel() {
    return Level.FULL;
  }

  @Bean
  public ObjectMapper objectMapper() {
    return new ObjectMapper()
        .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
        .registerModule(new Jackson2HalModule());
  }

  @Bean
  public MappingJackson2HttpMessageConverter converter() {
    final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

    converter.setSupportedMediaTypes(singletonList(HAL_JSON));
    converter.setObjectMapper(objectMapper());

    return converter;
  }

  @Bean
  public Decoder feignDecoder() {
    return new ResponseEntityDecoder(
        new SpringDecoder(
            () -> new HttpMessageConverters(converter())));
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文