使用Feign的@RequestLine功能

24

我有一个已定义的可用的Feign接口:

@FeignClient("content-link-service")
public interface ContentLinkServiceClient {

    @RequestMapping(method = RequestMethod.GET, value = "/{trackid}/links")
    List<Link> getLinksForTrack(@PathVariable("trackid") Long trackId);

}

如果我改用@RequestLine

@FeignClient("content-link-service")
public interface ContentLinkServiceClient {

    @RequestLine("GET /{trackid}/links")
    List<Link> getLinksForTrack(@Param("trackid") Long trackId);

}

我遇到了异常

Caused by: java.lang.IllegalStateException: Method getLinksForTrack not annotated with HTTP method type (ex. GET, POST)

为什么会出现这种情况?

4个回答

31

我不认为这会起作用。

@RequestLine 是 Feign 的核心注释,但您正在使用 Spring Cloud 的 @FeignClient,它使用 Spring MVC 注释。


22

Spring已经创建了自己的Feign Contract,让你可以使用Spring的@RequestMapping注释而不是Feign的。您可以通过在应用程序上下文中包含类型为feign.Contract.Default的bean来禁用此行为。

如果您正在使用spring-boot(或任何使用Java配置的内容),则在@Configuration类中包含此内容应该会重新启用Feign的注释:

@Bean
public Contract useFeignAnnotations() {
    return new Contract.Default();
}

2
在代码中我们应该在哪里调用useFeignAnnotations()呢?或者有没有内部bean会读取useFeignAnnotations()呢?我遇到了这个问题并在我的配置中添加了bean,但是像预期的那样它什么也没做。 - Alex
我也对这个很好奇。 - frlzjosh

2
我遇到这个错误的原因是我在我的FooClient接口中同时使用了@FeignClient@RequestLine注释。

修复之前。

import org.springframework.cloud.openfeign.FeignClient; // @FeignClient
import feign.RequestLine; //  @RequestLine
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("foo")
public interface FooClient {

    @RequestLine("GET /api/v1/foos/{fooId}")
    @Headers("Content-Type: application/json")
    ResponseEntity getFooById(@PathVariable("fooId") Long fooId); // I mistakenly used @PathVariable annotation here, but this should be @Param
}

然后,我遇到了这个错误。

Caused by: java.lang.IllegalStateException: Method FooClient#getFooById(Long) not annotated with HTTP method type (ex. GET, POST)

修复后

// removed @FeignClient
// removed @PathVariable
import feign.Param; // Added
import feign.RequestLine; //  @RequestLine

// removed @FeignClient("foo")
public interface FooClient {

    @RequestLine("GET /api/v1/foos/{fooId}")
    @Headers("Content-Type: application/json")
    Foo getFooById(@Param("fooId") Long fooId); // used @Param
}

如果您对配置类感兴趣。

  • 请注意,我尝试手动创建Feign客户端。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScans(value = {
        @ComponentScan(basePackages = {
                "com.example.app.service.web.client",
        })
})
public class FeignConfig {
    @Value(value = "${app.foo.service.client.url}")
    protected String url; // http://localhost:8081/app

    @Bean
    public FooClient fooClient() {
        FooClient fooClient = Feign.builder()
//                .client(RibbonClient.create())
                .client(new OkHttpClient())
                .encoder(new GsonEncoder())
                .decoder(new GsonDecoder())
                .logger(new Slf4jLogger(FooClient.class))
                .logLevel(Logger.Level.FULL)
                .target(FooClient.class, url);
        return fooClient;
    }
}

参考资料

  1. https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html
  2. https://www.baeldung.com/intro-to-feign
  3. https://www.baeldung.com/feign-requestline
  4. https://dev59.com/CV0a5IYBdhLWcg3wvq8y#32488372

-1

你的@RequestMapping值看起来没问题,但你可能需要稍微重写一下:

 @GetMapping(value = "/{trackid}/links")
 List<Link> getLinksForTrack(@PathVariable(name = "trackid") Long trackId);

顺便提一下,由于出现和你一样的错误,我没有成功地使用@RequestLine

此外,对于@ReactiveFeignClientsContract.Default()会产生以下错误:

java.lang.IllegalStateException: Method MyClient#doStuff(String,String) not annotated with HTTP method type (ex. GET, POST)
Warnings:
- Class MyClient has annotations [Component, ReactiveFeignClient, Metadata] that are not used by contract Default
- Method doStuff has an annotation GetMapping that is not used by contract Default

应该像这样修复:

var MyClient = WebReactiveFeign.builder()
        .contract(new ReactiveContract(new SpringMvcContract()))
        .target(MyClient, "http://example.com")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接