Open-Feign在实际工作中使用

现在我们公司的系统跟第三方合作比较多,所以难以避免的需要调用第三方接口,open-feign这个就非常实用,刚好总结一下,在实际工作中,如何方便地调用第三方接口。

引入Jar包

 
    org.springframework.cloud
    spring-cloud-starter-openfeign
    2.2.4.RELEASE



    io.github.openfeign
    feign-httpclient
    10.10.1

主要是引入openfeign,然后再用httpclient进行优化。

application配置

# 启用Httpclient
feign.httpclient.enabled=true
feign.httpclient.disable-ssl-validation=true
# 超时时间设置
feign.client.config.default.connectTimeout=5000
feign.client.config.default.readTimeout=5000

启用Feign

# 启动程序加入注解
@EnableFeignClients

Feign配置

基础配置

import feign.Client;
import feign.Feign;
import feign.Logger;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

@Configuration
public class FeignConfig {

    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }

    //绕过HTTPS
    @Bean
    public Feign.Builder feignBuilder() {
        final Client trustSSLSockets = client();
        return Feign.builder().client(trustSSLSockets);
    }

    public static SSLSocketFactory feignTrustingSSLSocketFactory = null;

    @Bean
    public Client client() {
        if(feignTrustingSSLSocketFactory==null){
            try {
                feignTrustingSSLSocketFactory = getFeignTrustingSSLSocketFactory();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return new Client.Default(feignTrustingSSLSocketFactory, new NoopHostnameVerifier());
    }

    public static SSLSocketFactory getFeignTrustingSSLSocketFactory() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[1];
        TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        return sc.getSocketFactory();
    }
    static class miTM implements TrustManager, X509TrustManager {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
        }

        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
        }
    }
}

调用第三方接口

@FeignClient(name = "feign-api",
        url = "http://localhost:8081/",
        configuration = {FeignConfig.class, FeignInterceptor.class})
public interface FeignApi {

    @GetMapping("/api/getToken")
    String getToken(@RequestParam("appKey") String appKey, @RequestParam("appSecret") String appSecret);

    @PostMapping("/api/pushInfo")
    String pushInfo(@RequestBody BoardMessage boardMessage);

    @PostMapping("/api/pushIndex")
    String pushIndex(@RequestBody WarnOrder warnOrder);
}

正常根据上面的代码,就能正常调用第三方接口,但是第三方接口做了token限制,就是token是15分钟失效,调用接口header必须携带token,所以我们还需要对上述代码做一些调整。

Token设置

Token的存储和获取

import java.util.concurrent.ConcurrentHashMap;

public class TokenStore {
    public static final String TOKEN = "token";

    public static final ConcurrentHashMap TOKEN_STORE = new ConcurrentHashMap<>(1);

    public static void saveToken(String token){
        TOKEN_STORE.put(TOKEN,token);
    }

    public static String getToken(){
        return TOKEN_STORE.get(TOKEN);
    }
}

Token 的调用

代码中要考虑到失效刷新和多线程并发问题

@Component
@Slf4j
public class RefreshToken {

    @Value("${appKey}")
    private String appKey;
    @Value("${appSecret}")
    private String appSecret;

    //60s
    public final long MAX_TIME_INTERVAL = 60;

    @Resource
    private FeignApi feignApi;

    public synchronized void makeSureNoExpireToken(){
        long currentTime = System.currentTimeMillis()/1000;
        if(null == TokenStore.getToken() ||
                (getExpireTime(TokenStore.getToken()) - currentTime) <= MAX_TIME_INTERVAL){
            // 获取Token
            String result = feignApi.getToken(appKey,appSecret);
            if(!StringUtils.isEmpty(result)){
                JSONObject jsonObject = JSONUtil.parseObj(result);
                if(jsonObject.getInt("code")==1){
                    log.info("正常获取Token");
                    TokenStore.saveToken(jsonObject.getStr("data"));
                }
            }
        }
    }

    private long getExpireTime(String token){
        JWT jwt = JWTUtil.parseToken(token);
        return jwt.getPayloads().getLong("exp");
    }
}

Feign中设置token

@Component
public class FeignInterceptor implements RequestInterceptor {

    @Resource
    private RefreshToken refreshToken;

    @Override
    public void apply(RequestTemplate template) {
        String url = template.url();
        log.info("apply url is : {}",url);
        if(!url.startsWith("/api/getToken")){
            String name = "token";
            // 1.先确保Token在有效期内  2.获取token
            refreshToken.makeSureNoExpireToken();
            String value = TokenStore.getToken();
            log.info("current the cloud token is : {}",value);
            //同理可以放入Cookie
            template.header(name, value);
        }
    }
}

这样我们就能正常调用第三方接口,而且不需要担心Token刷新问题。

你可能感兴趣的:(java)