使用Feign配置請求頭以及支持Https協議

Feign配置請求頭及支持Https協議

背景

最近跟第三方對接,請求頭需要特殊處理,同時是 Https 協議。

第三方提供的是使用 OkHttp 調用。同時呢,使用 OkHttp 封裝瞭調用和返回值。

今天對項目代碼進行審查的時候,想著還是把這個替換調吧,實現起來更加的優雅。

Feign配置請求頭

FeignParamsInterceptor 這個類實現瞭 RequestInterceptor ,可以實現對請求進行攔截處理。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; 
import java.io.UnsupportedEncodingException;
 
/**
 * @Description feign參數攔截
 */
@Component
public class FeignParamsInterceptor implements RequestInterceptor { 
    private static final Logger logger = LoggerFactory.getLogger(FeignParamsInterceptor.class);
    private static final String loanUrl = "x/";
    private static final String accountUrl = "y/";
 
    @Value("${xxxx}")
    private String clientSecret;
 
    @Value("${yyyy}")
    private String clientId;
 
    @Override
    public void apply(RequestTemplate requestTemplate) {
        String url = requestTemplate.url();
        if (url.contains(loanUrl) || url.contains(accountUrl)) {
            //獲取請求體
            byte[] body = requestTemplate.body();
            JSONObject params;
            try {
                params = JSON.parseObject(new String(body, requestTemplate.charset() == null ? "utf-8": requestTemplate.charset().name()));
                //設置請求體
                requestTemplate.body(params.toJSONString());
                requestTemplate.header("xx", CryptoEncrypt.signBytes(params.toJSONString().getBytes(), clientSecret.getBytes()));
                requestTemplate.header("yyyy", clientId);
                requestTemplate.header("Content-Type", "application/json;charset=utf-8");
            } catch (UnsupportedEncodingException e) {
                logger.info(e.getMessage(), e);
            }
        }
    } 
}

Feign支持Https協議

如下 FeignHttpsConfig 類內容:這個方案呢,目前是可以實現效果的。具體的內容是否可以簡化,優化。這個還沒有具體的研究。

本文的解決方案是有問題的。請點擊這裡

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.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
 
@Configuration
public class FeignHttpsConfig {
 
    @Bean
    public Feign.Builder feignBuilder() {
        final Client trustSSLSockets = client();
        return Feign.builder().client(trustSSLSockets);
    }
 
    @Bean
    public Client client(){
        return new Client.Default(
                TrustingSSLSocketFactory.get(), new NoopHostnameVerifier());
    }
}
 
class TrustingSSLSocketFactory extends SSLSocketFactory
        implements X509TrustManager, X509KeyManager {
 
    private static final Map<String, SSLSocketFactory> sslSocketFactories =
            new LinkedHashMap<String, SSLSocketFactory>();
    private static final char[] KEYSTORE_PASSWORD = "password".toCharArray();
    private final static String[] ENABLED_CIPHER_SUITES = {"TLS_RSA_WITH_AES_256_CBC_SHA"};
    private final SSLSocketFactory delegate;
    private final String serverAlias;
    private final PrivateKey privateKey;
    private final X509Certificate[] certificateChain;
 
    private TrustingSSLSocketFactory(String serverAlias) {
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(new KeyManager[] {this}, new TrustManager[] {this}, new SecureRandom());
            this.delegate = sc.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        this.serverAlias = serverAlias;
        if (serverAlias.isEmpty()) {
            this.privateKey = null;
            this.certificateChain = null;
        } else {
            try {
                KeyStore keyStore =
                        loadKeyStore(TrustingSSLSocketFactory.class.getResourceAsStream("/keystore.jks"));
                this.privateKey = (PrivateKey) keyStore.getKey(serverAlias, KEYSTORE_PASSWORD);
                Certificate[] rawChain = keyStore.getCertificateChain(serverAlias);
                this.certificateChain = Arrays.copyOf(rawChain, rawChain.length, X509Certificate[].class);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
 
    public static SSLSocketFactory get() {
        return get("");
    }
 
    public synchronized static SSLSocketFactory get(String serverAlias) {
        if (!sslSocketFactories.containsKey(serverAlias)) {
            sslSocketFactories.put(serverAlias, new TrustingSSLSocketFactory(serverAlias));
        }
        return sslSocketFactories.get(serverAlias);
    }
 
    static Socket setEnabledCipherSuites(Socket socket) {
        SSLSocket.class.cast(socket).setEnabledCipherSuites(ENABLED_CIPHER_SUITES);
        return socket;
    }
 
    private static KeyStore loadKeyStore(InputStream inputStream) throws IOException {
        try {
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(inputStream, KEYSTORE_PASSWORD);
            return keyStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            inputStream.close();
        }
    }
 
    @Override
    public String[] getDefaultCipherSuites() {
        return ENABLED_CIPHER_SUITES;
    }
 
    @Override
    public String[] getSupportedCipherSuites() {
        return ENABLED_CIPHER_SUITES;
    }
 
    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose)
            throws IOException {
        return setEnabledCipherSuites(delegate.createSocket(s, host, port, autoClose));
    }
 
    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return setEnabledCipherSuites(delegate.createSocket(host, port));
    }
 
    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return setEnabledCipherSuites(delegate.createSocket(host, port));
    }
 
    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
            throws IOException {
        return setEnabledCipherSuites(delegate.createSocket(host, port, localHost, localPort));
    }
 
    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
            throws IOException {
        return setEnabledCipherSuites(delegate.createSocket(address, port, localAddress, localPort));
    }
 
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
 
    @Override
    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
 
    @Override
    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
 
    @Override
    public String[] getClientAliases(String keyType, Principal[] issuers) {
        return null;
    }
 
    @Override
    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
        return null;
    }
 
    @Override
    public String[] getServerAliases(String keyType, Principal[] issuers) {
        return null;
    }
 
    @Override
    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
        return serverAlias;
    }
 
    @Override
    public X509Certificate[] getCertificateChain(String alias) {
        return certificateChain;
    }
 
    @Override
    public PrivateKey getPrivateKey(String alias) {
        return privateKey;
    }  
}

Feign client 設置請求頭信息

Feign client端

@FeignClient(url = "${test.url}", name = "cclient",configuration= ClientConfiguration.class,fallback = APIClientFallback.class)
public interface APIClient {        
    
    @RequestMapping(method = RequestMethod.POST, value = "/check/test")
    String checkResult(@RequestParam("sendTelNo") String sendTelNo,@RequestParam("certType") String certType,@RequestParam("certCode") String certCode,@RequestParam("userName") String userName);
    
    @RequestMapping(method = RequestMethod.POST, value = "/userstaus/test")
    String inusetime(@RequestParam("sendTelNo") String sendTelNo);    
    
    @RequestMapping(method = RequestMethod.POST, value = "/userstaus/test")
    String offnetIdentify(@RequestParam("sendTelNo") String sendTelNo,@RequestParam("date") String date);

配置文件 application-dev.yml

test:
      url: https://xxxxxx:8243/test
      tokenId: 11111112222222 

feign configuration 這裡配置全局的請求頭和token 

@Configuration
public class ClientConfiguration {
    
    @Value("${test.tokenId}")
    private String tokenId;
    
    @Bean
    public RequestInterceptor headerInterceptor() {
        return new RequestInterceptor(){
            @Override
            public void apply(RequestTemplate template) {
                List<String> authorizationList = Lists.newArrayList("Bearer "+tokenId);
                List<String> contentTypeList = Lists.newArrayList("application/x-www-form-urlencoded;charset=utf-8");
                Map<String, Collection<String>> headers =ImmutableMap.of("Authorization", authorizationList,"Content-Type", contentTypeList);
                template.headers(headers);
            }
        };
    }

feign 異常處理

@Component
public class APIClientFallback implements APIClient{
    @Override
    public String checkResult(String sendTelNo, String certType, String certCode, String userName) {
        return toJsonString();
    }
    @Override
    public String inusetime(String sendTelNo) {
        return toJsonString();
    }
    @Override
    public String offnetIdentify(String sendTelNo, String date) {
        return toJsonString();
    }
    private String toJsonString() {
        BaseResult resultVo = new BaseResult();
        resultVo.renderStatus(ResultTypeEnum.SERVICE_ERROR);
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(resultVo);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: