Feign学习笔记1-实战

Feign学习笔记

项目依赖

feign需要依赖eureka客户端。目前一定需要连上eureka,所以目前还没找到可不走euraka直连的方法(已有办法,看下篇博客),所以现在就走eureka好了。
依赖如下

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-codec-http</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-transprot-native-epoll</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

启动类

启动类其实并没有什么,只是@EnableEurekaClient 启动euraka客户端,@EnableFeignClients 启动feign客户端

@EnableEurekaClient
@EnableFeignClients
@SpringBootApplication
public class FeignMain {
    public static void main(String[] args) {
        SpringApplication.run(FeignMain.class, args);
    }
}

需要注意的是,使用euraka是需要在application.yml中配置spring.application.name: xxxxx。
此处只贴出了feign客户端的application.yml。服务提供方的feign就不贴了。

server.port: 10103

spring:
  application:
    name: feign

eureka:
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://xx.xx.xx.xx:10101/eureka/
  instance:
    instance-id: ${spring.cloud.client.ipAddress}:${server.port}
    prefer-ip-address: true
    lease-expiration-duration-in-seconds: 30
    lease-renewal-interval-in-seconds: 10

FeignClient

使用接口定义,然后加上@FeignClient(“服务提供放名称”)即可使用。其他语法与spring mvc相同

@FeignClient("rest-server")
public interface OrdinaryService {
    @RequestMapping(value = "/getNum")
    int getRandomInt();
}

实战细节

FeignClient默认RequestMethod是GET

@RequestMapping(value = "/getNum", method = RequestMethod.GET)
    public int getRandomInt() {
        Random random = new Random();
        Integer num = random.nextInt(100);
        logger.info("getRandomInt:" + num);
        return num;
    }

客户端使用如下方法调用

@RequestMapping(value = "/getNum")
    int getRandomInt();

如果将服务提供方的方法改为post,测试时会提示找不到方法。

默认参数使用RequestBody

GET转换为POST的是有比较复杂的原因,也有方法可以避免。后面详解。
原因简介:因为此处参数中没有加入注释所以参数是用的RequestBody。
服务提供方方法

@RequestMapping(value = "/addOne", method = RequestMethod.POST)
    public int addOne(@RequestBody int num) {
        return num + 1;
    }

客户端使用如下方法调用

@RequestMapping(value = "/addOne")
    int addOne(int num);

GET请求被转换为POST

如果上个方法中客户端调用没有写method = RequestMethod.POST,这里与默认使用GET方法有冲突?不,因为feign默认使用的HTTPClient是java自带的。这个http客户端会检查body中是否携带参数,如果有就会吧GET请求转换为POST。

将上面代码改为:
服务提供方方法

@RequestMapping(value = "/addOne", method = RequestMethod.GET)
    public int addOne(@RequestBody int num) {
        return num + 1;
    }

客户端使用如下方法调用

@RequestMapping(value = "/addOne", method = RequestMethod.GET)
    int addOne(int num);

结果出现

feign.FeignException: status 405 reading OrdinaryService#addOne(int); content:
{"timestamp":1501516961283,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/addOne"}

避免GET请求被转换成POST请求

实际上上面的方法将GET改为POST就可以正常使用,但是实际上开发中这样写还是非常别扭。比如,我有如下接口。
服务提供方方法

@RequestMapping(value = "/addTwo", method = RequestMethod.GET)
    public int addTwo(int num) {
        return num + 1;
    }

这么正常的方法,是在找不出理由去修改成为post。实际上调用方也是支持的
客户端使用如下方法调用

@RequestMapping(value = "/addTwo", method = RequestMethod.GET)
    int addTwo(@RequestParam("num") int num);

此处有坑
RequestParam中必须填写,如果不填写会出现

Caused by:java.lang.IllegalStateException:QueryMap parameter must be a map:class ....
nested exception is java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0

异常信息都是只截取了一半,但是都是关键信息
第一个异常是spring-cloud-netflix-core-1.2.6.RELEASE.jar会出现的。
第二个异常是spring-cloud-netflix-core-1.3.2.RELEASE.jar出现的。
其他版本应该差不多,虽然进化了好几个版本,但是主要问题依旧在于feign重写了RequestParam注解但是没有给予value默认值引起的。
所以使用RequestParam必须给予值,因为没有默认值

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值