近期https接口的联调小记
前不久跟第三方联调接口,涉及到了https协议,特记录一下备忘。
一、如何通过单向认证来访问对方的https接口?
- 创建信任库
对方会提供给你一个用于验证服务器证书的根证书或中间证书(.crt 或 .pem),你需要用它创建信任库。假如证书为ca.crt,那么需要执行以下命令,其中keytool的路径在jre的bin目录下。
keytool -import -trustcacerts -alias root-ca -file ca.crt -keystore mytruststore.jks -storepass 888888 -noprompt
- 在工具类中使用该信任库
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;import javax.annotation.PreDestroy;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;/*** 平台接口调用组件*/
@Component
public class PlatformInterfaceInvoker implements InitializingBean {/*** 日志打印*/private static final Logger LOG = LoggerFactory.getLogger(PlatformInterfaceInvoker.class);private CloseableHttpClient httpClient;// 创建共享的 HttpClientprivate CloseableHttpClient createSharedHttpClient() throws Exception {//可以将以下两项写入配置文件String truststorePath = "mytruststore.jks";char[] truststorePassword = "888888".toCharArray();KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());try (FileInputStream fis = new FileInputStream(truststorePath)) {trustStore.load(fis, truststorePassword);}SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build());// 配置连接池(根据实际业务需求调整)cm.setMaxTotal(200);cm.setDefaultMaxPerRoute(50);cm.setValidateAfterInactivity(30_000); // 30秒空闲验证return HttpClients.custom().setConnectionManager(cm).setConnectionManagerShared(true) // 共享连接池.setKeepAliveStrategy((response, context) -> 60_000) // 保持连接60秒.build();}/*** 简化版POST请求(默认JSON内容类型)** @param url 目标URL* @param jsonBody JSON格式的请求体* @return 响应内容* @throws IOException 如果请求失败*/public String postJson(String url, String jsonBody) throws Exception {HttpPost httpPost = new HttpPost(url);//设置JSON请求体和请求头StringEntity entity = new StringEntity(jsonBody, StandardCharsets.UTF_8);entity.setContentType("application/json");httpPost.setEntity(entity);httpPost.setHeader("Accept", "application/json");// 7. 发送HTTPS请求try (CloseableHttpResponse response = httpClient.execute(httpPost)) {HttpEntity responseEntity = response.getEntity();if (responseEntity != null) {String resultContent = EntityUtils.toString(responseEntity);LOG.info("向url={}发送post请求,请求参数={},响应结果={}", url, jsonBody, resultContent);}} catch (Exception e) {LOG.error("post请求异常: url={}, body={}", url, jsonBody, e);throw e;}return null;}@Overridepublic void afterPropertiesSet() throws Exception {this.httpClient = createSharedHttpClient();}// Spring 销毁时关闭连接池@PreDestroypublic void close() throws IOException {if (httpClient != null) {httpClient.close();LOG.info("HTTP client connection pool closed");}}}
二、如何向对方提供https接口?
首先方案不止一种,可以用Nginx代理,也可以直接用springBoot实现。采用后者比较简单。
- 为自己的服务生成密钥库
keytool -genkeypair -alias demo -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore demo_keystore.p12 -validity 3650 -dname "CN=demo" -ext "SAN=DNS:localhost,IP:127.0.0.1" -storepass changeit -keypass changeit
- 在application.properties中进行配置
server.port=8443server.ssl.enabled=trueserver.ssl.key-store-type=PKCS12server.ssl.key-store=classpath:keystore/demo_keystore.p12server.ssl.key-store-password=changeitserver.ssl.key-alias=demo