package com.doumee.core.utils;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.http.Header;
|
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpHost;
|
import org.apache.http.auth.AuthScope;
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
import org.apache.http.client.CredentialsProvider;
|
import org.apache.http.client.config.RequestConfig;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpRequestBase;
|
import org.apache.http.client.protocol.HttpClientContext;
|
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
import org.apache.http.entity.StringEntity;
|
import org.apache.http.impl.auth.DigestScheme;
|
import org.apache.http.impl.client.BasicAuthCache;
|
import org.apache.http.impl.client.BasicCredentialsProvider;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.util.EntityUtils;
|
|
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
import java.io.InputStream;
|
import java.net.URI;
|
import java.nio.charset.StandardCharsets;
|
import java.security.SecureRandom;
|
import java.security.cert.X509Certificate;
|
|
/**
|
* 海康 ISAPI HTTP 客户端(Digest 认证,支持 HTTP/HTTPS)
|
*/
|
@Slf4j
|
public class IsapiHttpUtil {
|
|
private static final int CONNECT_TIMEOUT = 10000;
|
private static final int SOCKET_TIMEOUT = 30000;
|
private static final int DOWNLOAD_SOCKET_TIMEOUT = 300000;
|
|
private IsapiHttpUtil() {
|
}
|
|
public static String doGet(String host, int port, String username, String password, String uri) {
|
return doGet(host, port, false, username, password, uri);
|
}
|
|
public static String doGet(String host, int port, boolean https, String username, String password, String uri) {
|
String url = buildUrl(host, port, https, uri);
|
HttpGet request = new HttpGet(url);
|
return executeString(request, host, port, https, username, password, SOCKET_TIMEOUT);
|
}
|
|
public static String doPost(String host, int port, String username, String password, String uri, String body, String contentType) {
|
return doPost(host, port, false, username, password, uri, body, contentType);
|
}
|
|
public static String doPost(String host, int port, boolean https, String username, String password,
|
String uri, String body, String contentType) {
|
String url = buildUrl(host, port, https, uri);
|
HttpPost request = new HttpPost(url);
|
if (body != null) {
|
request.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
|
}
|
if (contentType != null) {
|
request.setHeader("Content-Type", contentType);
|
}
|
return executeString(request, host, port, https, username, password, SOCKET_TIMEOUT);
|
}
|
|
public static String doPut(String host, int port, boolean https, String username, String password,
|
String uri, String body, String contentType) {
|
String url = buildUrl(host, port, https, uri);
|
HttpPut request = new HttpPut(url);
|
if (body != null) {
|
request.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
|
}
|
if (contentType != null) {
|
request.setHeader("Content-Type", contentType);
|
}
|
return executeString(request, host, port, https, username, password, SOCKET_TIMEOUT);
|
}
|
|
/**
|
* ISAPI 文件下载:GET /ISAPI/ContentMgmt/download?token=xxx,Body 含 playbackURI
|
*/
|
public static InputStream doDownload(String host, int port, String username, String password,
|
String uri, String downloadBody) {
|
return doDownload(host, port, false, username, password, uri, downloadBody);
|
}
|
|
public static InputStream doDownload(String host, int port, boolean https, String username, String password,
|
String uri, String downloadBody) {
|
String url = buildUrl(host, port, https, uri);
|
HttpGetWithEntity request = new HttpGetWithEntity(url);
|
if (downloadBody != null) {
|
request.setEntity(new StringEntity(downloadBody, StandardCharsets.UTF_8));
|
request.setHeader("Content-Type", "application/xml");
|
}
|
return executeStream(request, host, port, https, username, password, DOWNLOAD_SOCKET_TIMEOUT);
|
}
|
|
/** 海康 ISAPI 下载接口使用 GET + Body */
|
static class HttpGetWithEntity extends HttpEntityEnclosingRequestBase {
|
HttpGetWithEntity(String uri) {
|
setURI(URI.create(uri));
|
}
|
|
@Override
|
public String getMethod() {
|
return "GET";
|
}
|
}
|
|
private static String buildUrl(String host, int port, boolean https, String uri) {
|
String scheme = https ? "https" : "http";
|
if (!uri.startsWith("/")) {
|
uri = "/" + uri;
|
}
|
return scheme + "://" + host + ":" + port + uri;
|
}
|
|
private static String executeString(HttpRequestBase request, String host, int port, boolean https,
|
String username, String password, int socketTimeout) {
|
try (CloseableHttpClient httpClient = buildClient(https, buildCredentials(host, port, https, username, password));
|
CloseableHttpResponse response = execute(httpClient, request, host, port, https, username, password, socketTimeout)) {
|
HttpEntity entity = response.getEntity();
|
if (entity == null) {
|
return null;
|
}
|
return EntityUtils.toString(entity, StandardCharsets.UTF_8);
|
} catch (Exception e) {
|
log.error("ISAPI请求失败 {}: {}", request.getURI(), e.getMessage(), e);
|
return null;
|
}
|
}
|
|
private static InputStream executeStream(HttpRequestBase request, String host, int port, boolean https,
|
String username, String password, int socketTimeout) {
|
try {
|
CloseableHttpClient httpClient = buildClient(https, buildCredentials(host, port, https, username, password));
|
CloseableHttpResponse response = execute(httpClient, request, host, port, https, username, password, socketTimeout);
|
int status = response.getStatusLine().getStatusCode();
|
if (status < 200 || status >= 300) {
|
log.warn("ISAPI下载HTTP失败 {} status={}", request.getURI(), status);
|
EntityUtils.consumeQuietly(response.getEntity());
|
response.close();
|
httpClient.close();
|
return null;
|
}
|
HttpEntity entity = response.getEntity();
|
if (entity == null) {
|
response.close();
|
httpClient.close();
|
return null;
|
}
|
return entity.getContent();
|
} catch (Exception e) {
|
log.error("ISAPI下载失败 {}: {}", request.getURI(), e.getMessage(), e);
|
return null;
|
}
|
}
|
|
private static CredentialsProvider buildCredentials(String host, int port, boolean https,
|
String username, String password) {
|
CredentialsProvider credsProvider = new BasicCredentialsProvider();
|
String scheme = https ? "https" : "http";
|
credsProvider.setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM, scheme),
|
new UsernamePasswordCredentials(username, password));
|
credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
|
return credsProvider;
|
}
|
|
private static CloseableHttpResponse execute(CloseableHttpClient httpClient, HttpRequestBase request,
|
String host, int port, boolean https,
|
String username, String password, int socketTimeout) throws Exception {
|
RequestConfig requestConfig = RequestConfig.custom()
|
.setConnectTimeout(CONNECT_TIMEOUT)
|
.setSocketTimeout(socketTimeout)
|
.setConnectionRequestTimeout(CONNECT_TIMEOUT)
|
.build();
|
request.setConfig(requestConfig);
|
|
CredentialsProvider credsProvider = buildCredentials(host, port, https, username, password);
|
HttpHost httpHost = new HttpHost(host, port, https ? "https" : "http");
|
|
HttpClientContext context = HttpClientContext.create();
|
context.setCredentialsProvider(credsProvider);
|
|
log.info("ISAPI请求: {}://{}:{}{}", https ? "https" : "http", host, port, request.getURI().getRawPath());
|
CloseableHttpResponse response = httpClient.execute(httpHost, request, context);
|
int status = response.getStatusLine().getStatusCode();
|
if (status != 401) {
|
return response;
|
}
|
|
Header authHeader = findDigestAuthHeader(response);
|
if (authHeader == null) {
|
log.warn("ISAPI 401 但未返回 Digest 挑战头: {} status={}", request.getURI(), status);
|
return response;
|
}
|
|
EntityUtils.consumeQuietly(response.getEntity());
|
response.close();
|
|
DigestScheme digestScheme = new DigestScheme();
|
digestScheme.processChallenge(authHeader);
|
|
BasicAuthCache authCache = new BasicAuthCache();
|
authCache.put(httpHost, digestScheme);
|
|
HttpClientContext retryContext = HttpClientContext.create();
|
retryContext.setCredentialsProvider(credsProvider);
|
retryContext.setAuthCache(authCache);
|
|
CloseableHttpResponse retryResponse = httpClient.execute(httpHost, request, retryContext);
|
log.info("ISAPI Digest 重试: {} status={}", request.getURI(), retryResponse.getStatusLine().getStatusCode());
|
return retryResponse;
|
}
|
|
private static Header findDigestAuthHeader(CloseableHttpResponse response) {
|
Header[] headers = response.getHeaders("WWW-Authenticate");
|
if (headers == null || headers.length == 0) {
|
return null;
|
}
|
for (Header header : headers) {
|
if (header.getValue() != null && header.getValue().toLowerCase().contains("digest")) {
|
return header;
|
}
|
}
|
return headers[0];
|
}
|
|
private static CloseableHttpClient buildClient(boolean https, CredentialsProvider credsProvider) throws Exception {
|
HttpClientBuilder builder = HttpClients.custom().setDefaultCredentialsProvider(credsProvider);
|
if (!https) {
|
return builder.build();
|
}
|
TrustManager[] trustManagers = new TrustManager[]{
|
new X509TrustManager() {
|
@Override
|
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
}
|
|
@Override
|
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
}
|
|
@Override
|
public X509Certificate[] getAcceptedIssuers() {
|
return new X509Certificate[0];
|
}
|
}
|
};
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
sslContext.init(null, trustManagers, new SecureRandom());
|
SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
|
return builder.setSSLSocketFactory(sslFactory).build();
|
}
|
}
|