@FeignClient 實現簡便http請求封裝方式
@FeignClient實現http請求封裝
我們一般在代碼中調用http請求時,都是封裝瞭http調用類,底層自己定義請求頭,在寫的時候,也是需要對返回的值進行json解析,很不方便。
name
:name屬性會作為微服務的名稱,用於服務發現url
:host的意思,不用加http://前綴decode404
:當發生http 404錯誤時,如果該字段位true,會調用decoder進行解碼,否則拋出FeignException
使用流程
(1)創建接口類(FeignApi),來統一規范需要調用的第三方接口
@FeignClient(name = "aaa", url = "localhost:8080", decode404 = true) public interface FeignApi { /** * http請求 */ @PostMapping("/api/xxxx/baiduaaa") ResponseResult<ResponseVo> getSomeMoneyForYourSelfAAA(@RequestBody AAAParam param); /** * 模仿上面寫的Get方式請求 */ @GetMapping("/api/xxxx/baidubbb") ResponseResult<ResponseVo> getSomeMoneyForYourSelfBBB(@RequestBody AAAParam param); }
(2)在啟動類加上註解,會去掃包註冊Bean
@EnableFeignClients(basePackages = {"com.aaa"})
(3)業務代碼調用處:
ResponseResult<ResponseVo> response = pmsFeignApi.getSomeMoneyForYourSelfAAA(param);
將http請求封裝為FeignClient
1.配置攔截器
import java.io.IOException; import java.io.InterruptedIOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; public class OkHttpRetryInterceptor implements Interceptor {undefined private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpRetryInterceptor.class); /** * 最大重試次數 */ private int executionCount; /** * 重試的間隔 */ private long retryInterval; OkHttpRetryInterceptor(Builder builder) {undefined this.executionCount = builder.executionCount; this.retryInterval = builder.retryInterval; } @Override public Response intercept(Chain chain) throws IOException {undefined Request request = chain.request(); Response response = doRequest(chain, request); int retryNum = 0; while ((response == null || !response.isSuccessful()) && retryNum <= executionCount) {undefined LOGGER.info("intercept Request is not successful - {}", retryNum); final long nextInterval = getRetryInterval(); try {undefined LOGGER.info("Wait for {}", nextInterval); Thread.sleep(nextInterval); } catch (final InterruptedException e) {undefined Thread.currentThread().interrupt(); throw new InterruptedIOException(); } retryNum++; // retry the request response = doRequest(chain, request); } return response; } private Response doRequest(Chain chain, Request request) {undefined Response response = null; try {undefined response = chain.proceed(request); } catch (Exception e) {undefined } return response; } /** * retry間隔時間 */ public long getRetryInterval() {undefined return this.retryInterval; } public static final class Builder {undefined private int executionCount; private long retryInterval; public Builder() {undefined executionCount = 3; retryInterval = 1000; } public Builder executionCount(int executionCount) {undefined this.executionCount = executionCount; return this; } public Builder retryInterval(long retryInterval) {undefined this.retryInterval = retryInterval; return this; } public OkHttpRetryInterceptor build() {undefined return new OkHttpRetryInterceptor(this); } } }
2.註入feignClient bean
import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.netflix.feign.FeignAutoConfiguration; import org.springframework.cloud.netflix.feign.ribbon.CachingSpringLoadBalancerFactory; import org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.Client; import feign.Feign; import feign.ribbon.RibbonClient; import okhttp3.ConnectionPool; import okhttp3.OkHttpClient; @Configuration @ConditionalOnMissingBean({ OkHttpClient.class, Client.class }) @ConditionalOnClass(Feign.class) @AutoConfigureBefore(FeignAutoConfiguration.class) public class FeignClientConfig {undefined @Value("${feign.invoke.http.connectTimeoutMillis:3000}") private int connectTimeoutMillis; @Value("${feign.invoke.http.readTimeoutMillis:10000}") private int readTimeoutMillis; @Value("${feign.invoke.http.retryExecutionCount:3}") private int retryExecutionCount; @Value("${feign.invoke.http.retryInterval:1000}") private int retryInterval; public FeignClientConfig() {undefined } @Bean @ConditionalOnMissingBean({ OkHttpClient.class }) public OkHttpClient okHttpClient() {undefined OkHttpRetryInterceptor okHttpRetryInterceptor = new OkHttpRetryInterceptor.Builder().executionCount(retryExecutionCount) .retryInterval(retryInterval) .build(); return new OkHttpClient.Builder().retryOnConnectionFailure(true) .addInterceptor(okHttpRetryInterceptor) .connectionPool(new ConnectionPool()) .connectTimeout(connectTimeoutMillis, TimeUnit.MILLISECONDS) .readTimeout(readTimeoutMillis, TimeUnit.MILLISECONDS) .build(); } @Bean @ConditionalOnMissingBean({ Client.class }) public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) {undefined if (cachingFactory == null) {undefined RibbonClient.Builder builder = RibbonClient.builder(); builder.delegate(new feign.okhttp.OkHttpClient(this.okHttpClient())); return builder.build(); } else {undefined return new LoadBalancerFeignClient(new feign.okhttp.OkHttpClient(this.okHttpClient()), cachingFactory, clientFactory); } } }
3.配置pom引用
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-ribbon</artifactId> <version>9.0.0</version> </dependency>
4.寫feignClient
@FeignClient(name = "xxxApi", url = "${xxx.url}") public interface xxxClient { @RequestMapping(method = RequestMethod.POST) public String createLink(@RequestHeader(name = "accessKey", defaultValue = "xx") String accessKey, @RequestHeader(name = "accessSecret") String accessSecret, @RequestBody String linkConfig); }
5.寫熔斷器
@Autowired private xxxClient xxClient; @HystrixCommand(commandKey = "xxxLink", fallbackMethod = "xxxError", commandProperties = { @HystrixProperty(name = "requestCache.enabled", value = "true"), @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000") }) public String xxLink(String accessKey, String accessSecret, String linkConfig) { LOG.info("[xxLink] LinkConfig is {}", linkConfig); String resp = xxxClient.createLink(accessKey, accessSecret, linkConfig); LOG.info("[xxxLink] response : {}", resp); return resp; }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 完美解決SpringCloud-OpenFeign使用okhttp替換不生效問題
- 解決Feign切換client到okhttp無法生效的坑(出現原因說明)
- Android基於OkHttp實現文件上傳功能
- 淺談SpringCloud feign的http請求組件優化方案
- Spring Cloud超詳細i講解Feign自定義配置與使用