最近在項目中使用FeignClient發https(s)請求的時候發現一個非常奇怪的問題,在上一個文章我寫了將項目中的OkHttpClient替換成FeignClient,這樣能使的代碼好看,易於維護。但是在替換的過程中發現,有一小部分替換之后發不了請求,使用OkHttpClient時可以返回正常的數據,但是使用FeignClient時則提示403,具體的信息如下:
這個是FeignClient的日志:
這個是錯誤信息:
為了檢查是否由於Cookie或者request header的問題導致的,使用curl命令請求,如下:
上半部分是curl命令,可以發現我只攜帶了一個請求頭「authorization」,其他什么都沒有設置了,也是可以獲得正確的返回值。由於返回的信息部分屬於公司財產,所以打碼比較多,見諒
然后在debug的時候,發現FeignClient使用的是默認的客戶端「feign.client.Default
」,我就想切換成「OkHttpClient」,按照網上的教程
- 導入依賴
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
2. 修改配置文件
feign: httpclient: enabled: true
完成上述配置之后重新測試,還是使用的「feign.client.Default
」,默認的客戶端。
之后查看FeignClientAutoConfiguration類,部分如下:
也就說在配置了{feign.okhttp.enabled=true}時,還需要判斷當前容器中是否含有OkHttpClient類的對象,如果沒有,則啟動配置類;如果有,則配置類不生效。
所以,既然配置類不生效,那么最簡單暴力的方式就是將「OkHttpFeignConfiguration」里面的信息都拷貝出來,然后自定義一個配置類。
完整的配置類代碼如下:
import feign.Client; import feign.Feign; import okhttp3.ConnectionPool; import okhttp3.OkHttpClient; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory; import org.springframework.cloud.commons.httpclient.OkHttpClientFactory; import org.springframework.cloud.openfeign.FeignAutoConfiguration; import org.springframework.cloud.openfeign.support.FeignHttpClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.TimeUnit; @Configuration @ConditionalOnClass(Feign.class) @AutoConfigureBefore(FeignAutoConfiguration.class) public class FeignOkHttpConfig { @Bean @ConditionalOnMissingBean({Client.class}) public Client feignClient(okhttp3.OkHttpClient client) { return new feign.okhttp.OkHttpClient(client); } @Bean @ConditionalOnMissingBean({ConnectionPool.class}) public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) { Integer maxTotalConnections = httpClientProperties.getMaxConnections(); Long timeToLive = httpClientProperties.getTimeToLive(); TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit(); return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit); } @Bean public OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) { Boolean followRedirects = httpClientProperties.isFollowRedirects(); Integer connectTimeout = httpClientProperties.getConnectionTimeout(); Boolean disableSslValidation = httpClientProperties.isDisableSslValidation(); return httpClientFactory.createBuilder(disableSslValidation) .connectTimeout((long)connectTimeout, TimeUnit.SECONDS) .followRedirects(followRedirects) .connectionPool(connectionPool) .build(); } }
重啟之后再次測試,成功解決問題。