0%

Feign Client 访问统一API Response

一、什么是Feign

呃,这是一个好东西。

我们平常访问远端Restful API时,都是使用OKHttpClient之类的库去访问HTTP Restful API,其实挺类的,既要了解方法,又要了解参数转换,然后写一堆请求代码和数据转换代码,非常不友好。

Feign就是一个解救我们于Restful API请求水深火热中的神器。

二、Feign是怎么做的?

Feign给要请求的API定义成Service Interface

1
2
3
4
interface UserAPI {
@RequestLine("GET /user/{id}")
UserVO fetchDetail(@Param("id") String id);
}

在使用时,我们直接使用即可:

1
2
3
4
5
6
7
8
9
10
11
12
class SomeAPI {
private final UserAPI userAPI;

public SomeAPI(UserAPI userAPI) {
this.userAPI = userAPI;
}

@GetMapping("/{id}")
public UserVO xxx(@PathVarable("id") String id) {
return userAPI.fetchDetail(id);
}
}

当然,要让上面的代码有效,我们还需要对UserAPI实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import am.pc.support.feign.deployment_performer.MerchantService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static am.pc.support.config.FeignHelper.build;

/**
* API Configuration
*
* @author kut
*/
@Configuration
public class ApiConfiguration {

@Value("${feign.service_url}")
private String serviceUrl;

@Bean
public MerchantService buildMerchantService() {
return build(UserAPI.class, serviceUrl);
}

/**
* build
*
* @param clazz service class
* @param serviceUrl service url
* @param <T> service class
* @return result
*/
public static <T> T build(Class<T> clazz, String serviceUrl) {
return Feign.builder()
.decoder(new ApiFeignDecoder())
.target(clazz, serviceUrl);
}
}

三、如果使用了全局Response呢?

传统的Feign Client获取到的数据都是数据本身,而使用了Repsonse之后,数据被包在Response之中,所以,我们需要对Feign进行定制化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import feign.FeignException;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

/**
* API feign decoder
*
* @author kut
*/
@Slf4j
public class ApiFeignDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) throws IOException, FeignException {
String data = IOUtils.toString(response.body().asInputStream(), StandardCharsets.UTF_8);
JSONObject json = JSON.parseObject(data);
if (json.getInteger("code") != 0) {
log.error(
"request {} failure: {} - {}",
response.request(),
json.getInteger("code"),
json.getString("error")
);
throw new DecodeException(
json.getInteger("code"),
json.getString("error"),
response.request()
);
}

// 将data转成数据返回
return json.getJSONObject("data").toJavaObject(type);
}
}

四、总结

Feign Client相当好用,同时配合global response,相当的有趣。