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必須給予值,因爲沒有默認值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章