前一篇,我们解决了Spring的RestTemplate在发送Get请求不能传递body,相比RestTemplate,我们更多的还是采用更方便的申明式服务调用框架Feign。本篇不会介绍Feign,而是解决Feign发送Get请求时仍然不能传递body的问题。

1. 准备

在这里,我使用的Spring boot的版本为1.5.10.RELEASE,Spring Cloud版本为Edgware.SR3

准备三个服务:注册中心、服务生产者、服务消费,这里我们继续使用在 Spring Cloud服务注册中心Eureka定义的三个服务:服务注册中心01-eureka-server、服务提供者01-service-demo,同时新建一个服务消费者01-feign-consumer,使用feign来请求服务而不是ribbon,记得在启动类加上@EnableFeignClients启用Feign。

1、在服务提供者01-service-demo添加一个接口,代码如下:

@GetMapping("/hello/user")
public String sayHello(@RequestBody User user) {
    return "hello, " + user.getName() + ", give you a gift " + user.getGift();
}

这样,Get请求需要接收body数据。

2、在服务消费者01-feign-consumer编写如下代码:

(1)在SayHelloClient中添加如下声明式服务请求:

@FeignClient("hello-service")
public interface SayHelloClient {
    @GetMapping(value = "/hello/user")
    String sayHello(@RequestBody User user);
}

(2)在SayHelloController中调用SayHelloClient

@RestController
public class SayHelloController {
    private static Logger log = LoggerFactory.getLogger(SayHelloController.class);

    @Autowired
    private ApiProductClient apiProductClient;

    @GetMapping("/user")
    public String userHello() {
        User user = new User();
        user.setName("lily");
        user.setGift("birthday card");
        return sayHelloClient.sayHello(user);
    }
}

3、分别启动服务注册中心01-eureka-server、服务提供者01-service-demo,服务消费者01-feign-consumer,浏览器访问http://localhost:9091/user,后台先错误信息:

feign.FeignException: status 405 reading SayHelloClient#sayHello(User); content:
{"timestamp":1548141786602,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/hello/user"}
    at feign.FeignException.errorStatus(FeignException.java:62) ~[feign-core-9.5.0.jar:na]
    at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:91) ~[feign-core-9.5.0.jar:na]
……

意思是请求的Post方法不被允许,很明显,我们后台必须接收Get请求,而非Post。

2. 原因

同RestTemplate类似,Feign默认情况下也使用的是JDK原生的http请求,同时也支持OkHttp、HttpClient等框架。默认情况下,原生Http请求不允许Get请求传递body,如果传递了body数据,会将当前请求转为Post请求,而实际上我们后台接收的是Get请求,所以抛出上边的异常,所以我们需要换成能够支持的HttpClient。

3. 解决

1、在服务消费者01-feign-consumer的pom.xml中引入第三方依赖包:

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>9.4.0</version>
</dependency>

2、在服务消费者01-feign-consumer的配置文件中启用httpclient:

# feign use httpclient
feign.httpclient.enabled=true

3、测试:

分别启动服务注册中心01-eureka-server、服务提供者01-service-demo,服务消费者01-feign-consumer,浏览器再次访问http://localhost:9091/user,可以看到输出了正确的信息:

99cda8e9bed24932ac1da422e5366ffd

问题解决。

示例代码: github


相关阅读