org.aoju.bus.http.Httpd Maven / Gradle / Ivy
/*
* The MIT License
*
* Copyright (c) 2015-2020 aoju.org All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.aoju.bus.http;
import org.aoju.bus.core.io.Sink;
import org.aoju.bus.core.io.Source;
import org.aoju.bus.http.accord.*;
import org.aoju.bus.http.accord.platform.Platform;
import org.aoju.bus.http.cache.Cache;
import org.aoju.bus.http.cache.InternalCache;
import org.aoju.bus.http.metric.CookieJar;
import org.aoju.bus.http.metric.Dispatcher;
import org.aoju.bus.http.metric.EventListener;
import org.aoju.bus.http.metric.Interceptor;
import org.aoju.bus.http.metric.proxy.NullProxySelector;
import org.aoju.bus.http.secure.Authenticator;
import org.aoju.bus.http.secure.CertificateChainCleaner;
import org.aoju.bus.http.secure.CertificatePinner;
import org.aoju.bus.http.secure.OkHostnameVerifier;
import org.aoju.bus.http.socket.RealWebSocket;
import org.aoju.bus.http.socket.WebSocket;
import org.aoju.bus.http.socket.WebSocketListener;
import javax.net.SocketFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 发送HTTP请求辅助类
* 工厂的{@linkplain NewCall calls},可以用来发送HTTP请求并读取它们的响应
* 当您创建一个{@code Httpd}实例并将其用于所有HTTP调用时,体现Httpd的性能最佳
* 这是因为每个客户机都拥有自己的连接池和线程池。重用连接和线程可以减少延迟并节省内存
* 相反,为每个请求创建一个客户机会浪费空闲池上的资源
* Httpd还为HTTP/2连接使用守护进程线程。如果它们保持空闲,就会自动退出
*
* @author Kimi Liu
* @version 5.6.5
* @since JDK 1.8+
*/
public class Httpd implements Cloneable, NewCall.Factory, WebSocket.Factory {
static final List DEFAULT_PROTOCOLS = org.aoju.bus.http.Builder.immutableList(
Protocol.HTTP_2, Protocol.HTTP_1_1);
static final List DEFAULT_CONNECTION_SPECS = org.aoju.bus.http.Builder.immutableList(
ConnectionSuite.MODERN_TLS, ConnectionSuite.CLEARTEXT);
static {
org.aoju.bus.http.Builder.instance = new org.aoju.bus.http.Builder() {
@Override
public void addLenient(Headers.Builder builder, String line) {
builder.addLenient(line);
}
@Override
public void addLenient(Headers.Builder builder, String name, String value) {
builder.addLenient(name, value);
}
@Override
public void setCache(Builder builder, InternalCache internalCache) {
builder.setInternalCache(internalCache);
}
@Override
public boolean connectionBecameIdle(
ConnectionPool pool, RealConnection connection) {
return pool.connectionBecameIdle(connection);
}
@Override
public RealConnection get(ConnectionPool pool, Address address,
StreamAllocation streamAllocation, Route route) {
return pool.get(address, streamAllocation, route);
}
@Override
public boolean equalsNonHost(Address a, Address b) {
return a.equalsNonHost(b);
}
@Override
public Socket deduplicate(
ConnectionPool pool, Address address, StreamAllocation streamAllocation) {
return pool.deduplicate(address, streamAllocation);
}
@Override
public void put(ConnectionPool pool, RealConnection connection) {
pool.put(connection);
}
@Override
public RouteDatabase routeDatabase(ConnectionPool connectionPool) {
return connectionPool.routeDatabase;
}
@Override
public int code(Response.Builder responseBuilder) {
return responseBuilder.code;
}
@Override
public void apply(ConnectionSuite tlsConfiguration, SSLSocket sslSocket, boolean isFallback) {
tlsConfiguration.apply(sslSocket, isFallback);
}
@Override
public boolean isInvalidHttpUrlHost(IllegalArgumentException e) {
return e.getMessage().startsWith(UnoUrl.Builder.INVALID_HOST);
}
@Override
public StreamAllocation streamAllocation(NewCall call) {
return ((RealCall) call).streamAllocation();
}
@Override
public IOException timeoutExit(NewCall call, IOException e) {
return ((RealCall) call).timeoutExit(e);
}
@Override
public NewCall newWebSocketCall(Httpd client, Request originalRequest) {
return RealCall.newRealCall(client, originalRequest, true);
}
};
}
final Dispatcher dispatcher;
final Proxy proxy;
final List protocols;
final List connectionSuites;
/**
* 返回一个不可变的拦截器列表,该列表观察每个调用的完整跨度:
* 从建立连接之前(如果有的话)到选择响应源之后(源服务器、缓存或两者都有)
*/
final List interceptors;
/**
* 返回观察单个网络请求和响应的不可变拦截器列表。这些拦截器必须
* 调用{@link Interceptor.Chain#proceed} 只执行一次:网络拦截器短路或重复网络请求是错误的
*/
final List networkInterceptors;
final EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector;
final CookieJar cookieJar;
final Cache cache;
final InternalCache internalCache;
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
final CertificateChainCleaner certificateChainCleaner;
final HostnameVerifier hostnameVerifier;
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
final ConnectionPool connectionPool;
final DnsX dns;
final boolean followSslRedirects;
final boolean followRedirects;
final boolean retryOnConnectionFailure;
/**
* 默认调用超时(毫秒).
*/
final int callTimeout;
/**
* 默认连接超时(毫秒).
*/
final int connectTimeout;
/**
* 默认读超时(毫秒).
*/
final int readTimeout;
/**
* 默认写超时(毫秒).
*/
final int writeTimeout;
/**
* Web socket ping间隔(毫秒)
*/
final int pingInterval;
public Httpd() {
this(new Builder());
}
Httpd(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSuites = builder.connectionSuites;
this.interceptors = org.aoju.bus.http.Builder.immutableList(builder.interceptors);
this.networkInterceptors = org.aoju.bus.http.Builder.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSuite spec : connectionSuites) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = org.aoju.bus.http.secure.X509TrustManager.platformTrustManager();
this.sslSocketFactory = newSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
if (sslSocketFactory != null) {
Platform.get().configureSslSocketFactory(sslSocketFactory);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.callTimeout = builder.callTimeout;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
private static SSLSocketFactory newSslSocketFactory(X509TrustManager trustManager) {
try {
SSLContext sslContext = Platform.get().getSSLContext();
sslContext.init(null, new TrustManager[]{trustManager}, null);
return sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw org.aoju.bus.http.Builder.assertionError("No System TLS", e);
}
}
@Override
public NewCall newCall(Request request) {
return RealCall.newRealCall(this, request, false);
}
@Override
public WebSocket newWebSocket(Request request, WebSocketListener listener) {
RealWebSocket webSocket = new RealWebSocket(request, listener, new Random(), pingInterval);
webSocket.connect(this);
return webSocket;
}
public int callTimeoutMillis() {
return callTimeout;
}
public int connectTimeoutMillis() {
return connectTimeout;
}
public int readTimeoutMillis() {
return readTimeout;
}
public int writeTimeoutMillis() {
return writeTimeout;
}
public int pingIntervalMillis() {
return pingInterval;
}
public Proxy proxy() {
return proxy;
}
public ProxySelector proxySelector() {
return proxySelector;
}
public CookieJar cookieJar() {
return cookieJar;
}
public Cache cache() {
return cache;
}
InternalCache internalCache() {
return cache != null ? cache.internalCache : internalCache;
}
public DnsX dns() {
return dns;
}
public SocketFactory socketFactory() {
return socketFactory;
}
public SSLSocketFactory sslSocketFactory() {
return sslSocketFactory;
}
public HostnameVerifier hostnameVerifier() {
return hostnameVerifier;
}
public CertificatePinner certificatePinner() {
return certificatePinner;
}
public Authenticator authenticator() {
return authenticator;
}
public Authenticator proxyAuthenticator() {
return proxyAuthenticator;
}
public ConnectionPool connectionPool() {
return connectionPool;
}
public boolean followSslRedirects() {
return followSslRedirects;
}
public boolean followRedirects() {
return followRedirects;
}
public boolean retryOnConnectionFailure() {
return retryOnConnectionFailure;
}
public Dispatcher dispatcher() {
return dispatcher;
}
public List protocols() {
return protocols;
}
public List connectionSpecs() {
return connectionSuites;
}
public List interceptors() {
return interceptors;
}
public List networkInterceptors() {
return networkInterceptors;
}
public EventListener.Factory eventListenerFactory() {
return eventListenerFactory;
}
public Builder newBuilder() {
return new Builder(this);
}
public static final class Builder {
final List interceptors = new ArrayList<>();
final List networkInterceptors = new ArrayList<>();
Dispatcher dispatcher;
Proxy proxy;
List protocols;
List connectionSuites;
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
Cache cache;
InternalCache internalCache;
SocketFactory socketFactory;
SSLSocketFactory sslSocketFactory;
CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator;
Authenticator authenticator;
ConnectionPool connectionPool;
DnsX dns;
boolean followSslRedirects;
boolean followRedirects;
boolean retryOnConnectionFailure;
int callTimeout;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSuites = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = DnsX.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
Builder(Httpd httpd) {
this.dispatcher = httpd.dispatcher;
this.proxy = httpd.proxy;
this.protocols = httpd.protocols;
this.connectionSuites = httpd.connectionSuites;
this.interceptors.addAll(httpd.interceptors);
this.networkInterceptors.addAll(httpd.networkInterceptors);
this.eventListenerFactory = httpd.eventListenerFactory;
this.proxySelector = httpd.proxySelector;
this.cookieJar = httpd.cookieJar;
this.internalCache = httpd.internalCache;
this.cache = httpd.cache;
this.socketFactory = httpd.socketFactory;
this.sslSocketFactory = httpd.sslSocketFactory;
this.certificateChainCleaner = httpd.certificateChainCleaner;
this.hostnameVerifier = httpd.hostnameVerifier;
this.certificatePinner = httpd.certificatePinner;
this.proxyAuthenticator = httpd.proxyAuthenticator;
this.authenticator = httpd.authenticator;
this.connectionPool = httpd.connectionPool;
this.dns = httpd.dns;
this.followSslRedirects = httpd.followSslRedirects;
this.followRedirects = httpd.followRedirects;
this.retryOnConnectionFailure = httpd.retryOnConnectionFailure;
this.callTimeout = httpd.callTimeout;
this.connectTimeout = httpd.connectTimeout;
this.readTimeout = httpd.readTimeout;
this.writeTimeout = httpd.writeTimeout;
this.pingInterval = httpd.pingInterval;
}
/**
* 设置完成调用的默认超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param timeout 超时时间
* @param unit 计算单位
* @return 构造器
*/
public Builder callTimeout(long timeout, TimeUnit unit) {
callTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
return this;
}
/**
* 设置完成调用的默认超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param duration 持续时间
* @return 构造器
*/
public Builder callTimeout(Duration duration) {
callTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
return this;
}
/**
* 设置新连接的默认连接超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param timeout 超时时间
* @param unit 计算单位
* @return 构造器
*/
public Builder connectTimeout(long timeout, TimeUnit unit) {
connectTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
return this;
}
/**
* 设置新连接的默认连接超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param duration 持续时间
* @return 构造器
*/
public Builder connectTimeout(Duration duration) {
connectTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
return this;
}
/**
* 设置新连接的默认读取超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param timeout 超时时间
* @param unit 计算单位
* @return 构造器
* @see Socket#setSoTimeout(int)
* @see Source#timeout()
*/
public Builder readTimeout(long timeout, TimeUnit unit) {
readTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
return this;
}
/**
* 设置新连接的默认读取超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param duration 持续时间
* @return 构造器
* @see Socket#setSoTimeout(int)
* @see Source#timeout()
*/
public Builder readTimeout(Duration duration) {
readTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
return this;
}
/**
* 设置新连接的默认写超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param timeout 超时时间
* @param unit 计算单位
* @return 构造器
* @see Sink#timeout()
*/
public Builder writeTimeout(long timeout, TimeUnit unit) {
writeTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", timeout, unit);
return this;
}
/**
* 设置新连接的默认写超时。值0表示没有超时,否则在转换为毫秒时,值必须在1和{@link Integer#MAX_VALUE}之间
*
* @param duration 持续时间
* @return 构造器
* @see Sink#timeout()
*/
public Builder writeTimeout(Duration duration) {
writeTimeout = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
return this;
}
/**
* 设置此客户端发起的HTTP/2和web套接字ping之间的间隔。使用此命令可自动发送ping帧,直到连接失败或关闭
* 这将保持连接处于活动状态,并可能检测到连接失败.
*
* @param interval 间隔时间
* @param unit 计算单位
* @return 构造器
*/
public Builder pingInterval(long interval, TimeUnit unit) {
pingInterval = org.aoju.bus.http.Builder.checkDuration("interval", interval, unit);
return this;
}
/**
* 设置此客户端发起的HTTP/2和web套接字ping之间的间隔。使用此命令可自动发送ping帧,
* 直到连接失败或关闭。这将保持连接处于活动状态,并可能检测到连接失败.
*
* @param duration 持续时间
* @return 构造器
*/
public Builder pingInterval(Duration duration) {
pingInterval = org.aoju.bus.http.Builder.checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS);
return this;
}
/**
* 设置此客户端创建的连接将使用的HTTP代理。它优先于{@link #proxySelector},
* 后者仅在此代理为空(默认为空)时才被启用。要完全禁用代理使用,请调用{@code proxy(proxy . no_proxy)}
*
* @param proxy 代理
* @return 构造器
*/
public Builder proxy(Proxy proxy) {
this.proxy = proxy;
return this;
}
/**
* 如果没有显式指定{@link #proxy proxy},则设置要使用的代理选择策略。代理选择器可以返回多个代理;在这种情况下,
* 将依次对它们进行测试,直到建立成功的连接.
*
* @param proxySelector 代理选择器
* @return 构造器
*/
public Builder proxySelector(ProxySelector proxySelector) {
if (proxySelector == null) throw new NullPointerException("proxySelector == null");
this.proxySelector = proxySelector;
return this;
}
/**
* 设置可以接受来自传入HTTP响应的cookie并向传出HTTP请求提供cookie的处理程序.
*
* @param cookieJar cookie策略
* @return 构造器
*/
public Builder cookieJar(CookieJar cookieJar) {
if (cookieJar == null) throw new NullPointerException("cookieJar == null");
this.cookieJar = cookieJar;
return this;
}
/**
* 设置用于读写缓存的响应的响应缓存.
*
* @param internalCache 响应缓存
*/
void setInternalCache(InternalCache internalCache) {
this.internalCache = internalCache;
this.cache = null;
}
/**
* 设置用于读写缓存的响应的响应缓存.
*
* @param cache 缓存支持
* @return 构造器
*/
public Builder cache(Cache cache) {
this.cache = cache;
this.internalCache = null;
return this;
}
/**
* 设置用于查找主机名的IP地址的DNS服务.
* 如果未设置,将使用{@link DnsX#SYSTEM system-wide default}DNS
*
* @param dns DNS服务
* @return 构造器
*/
public Builder dns(DnsX dns) {
if (dns == null) throw new NullPointerException("dns == null");
this.dns = dns;
return this;
}
/**
* 设置用于创建连接的套接字工厂。Httpd只使用无参数的{@link SocketFactory#createSocket()}
* 方法来创建未连接的套接字。重写这个方法,例如。,允许将套接字绑定到特定的本地地址
* 如果未设置,将使用{@link SocketFactory#getDefault() system-wide default}socket工厂
*
* @param socketFactory socket工厂
* @return 构造器
*/
public Builder socketFactory(SocketFactory socketFactory) {
if (socketFactory == null) throw new NullPointerException("socketFactory == null");
this.socketFactory = socketFactory;
return this;
}
/**
* 设置用于保护HTTPS连接的套接字工厂。如果未设置,则使用系统默认值
*
* @param sslSocketFactory socket工厂
* @return 构造器
*/
public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) {
if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
this.sslSocketFactory = sslSocketFactory;
this.certificateChainCleaner = Platform.get().buildCertificateChainCleaner(sslSocketFactory);
return this;
}
/**
* 设置用于保护HTTPS连接的套接字工厂和信任管理器。如果未设置,则使用系统默认值
* 大多数应用程序不应该调用这个方法,而应该使用系统默认值。这些类包含特殊的优化,如果实现被修饰,这些优化可能会丢失
*
* {@code
*
* TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
* TrustManagerFactory.getDefaultAlgorithm());
* trustManagerFactory.init((KeyStore) null);
* TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
* if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
* throw new IllegalStateException("Unexpected default trust managers:"
* + Arrays.toString(trustManagers));
* }
* X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
*
* SSLContext sslContext = SSLContext.getInstance("TLS");
* sslContext.init(null, new TrustManager[] { trustManager }, null);
* SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
*
* Httpd client = new Httpd.Builder()
* .sslSocketFactory(sslSocketFactory, trustManager)
* .build();
* }
*
*
* @param sslSocketFactory ssl socket工厂
* @param trustManager X509证书身份验证
* @return 构造器
*/
public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
if (trustManager == null) throw new NullPointerException("trustManager == null");
this.sslSocketFactory = sslSocketFactory;
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
return this;
}
/**
* 设置用于确认响应证书适用于HTTPS连接请求的主机名的验证程序.
* 如果未设置,将使用默认的主机名验证器
*
* @param hostnameVerifier 验证主机名接口
* @return 构造器
*/
public Builder hostnameVerifier(HostnameVerifier hostnameVerifier) {
if (hostnameVerifier == null) throw new NullPointerException("hostnameVerifier == null");
this.hostnameVerifier = hostnameVerifier;
return this;
}
/**
* 设置限制哪些证书受信任的证书pinner。默认情况下,HTTPS连接仅
* 依赖于{@link #sslSocketFactory SSL套接字工厂}来建立信任。
* 固定证书避免了信任证书颁发机构的需要。
*
* @param certificatePinner 证书
* @return 构造器
*/
public Builder certificatePinner(CertificatePinner certificatePinner) {
if (certificatePinner == null) throw new NullPointerException("certificatePinner == null");
this.certificatePinner = certificatePinner;
return this;
}
/**
* 设置用于响应来自源服务器的挑战的验证器。使用{@link #proxyAuthenticator}设置代理服务器的身份验证器.
*
* @param authenticator 验证器
* @return 构造器
*/
public Builder authenticator(Authenticator authenticator) {
if (authenticator == null) throw new NullPointerException("authenticator == null");
this.authenticator = authenticator;
return this;
}
/**
* 设置用于响应来自代理服务器的挑战的验证器。使用{@link #authenticator}设置源服务器的身份验证器
* 果未设置,将尝试{@linkplain Authenticator#NONE no authentication will be attempted}
*
* @param proxyAuthenticator 代理验证器
* @return 构造器
*/
public Builder proxyAuthenticator(Authenticator proxyAuthenticator) {
if (proxyAuthenticator == null) throw new NullPointerException("proxyAuthenticator == null");
this.proxyAuthenticator = proxyAuthenticator;
return this;
}
/**
* 设置用于回收HTTP和HTTPS连接的连接池.
* 如果未设置,将使用新的连接池
*
* @param connectionPool 连接池信息
* @return 构造器
*/
public Builder connectionPool(ConnectionPool connectionPool) {
if (connectionPool == null) throw new NullPointerException("connectionPool == null");
this.connectionPool = connectionPool;
return this;
}
/**
* 让这个客户从HTTPS到HTTPS跟踪和从HTTPS到HTTPS.
* 如果未设置,将遵循协议重定向。这与内置的{@code HttpURLConnection}的默认设置不同
*
* @param followProtocolRedirects 重定向
* @return 构造器
*/
public Builder followSslRedirects(boolean followProtocolRedirects) {
this.followSslRedirects = followProtocolRedirects;
return this;
}
/**
* 此客户端配置为遵循重定向。如果未设置,将遵循重定向.
*
* @param followRedirects 重定向
* @return 构造器
*/
public Builder followRedirects(boolean followRedirects) {
this.followRedirects = followRedirects;
return this;
}
/**
* 在遇到连接问题时,将此客户端配置为重试或不重试
* 将此设置为false,以避免在这样做会造成破坏时重试请求
* 在这种情况下,调用应用程序应该自己恢复连接故障.
*
* @param retryOnConnectionFailure 失败重试
* @return 构造器
*/
public Builder retryOnConnectionFailure(boolean retryOnConnectionFailure) {
this.retryOnConnectionFailure = retryOnConnectionFailure;
return this;
}
/**
* 设置用于设置策略和执行异步请求的调度程序。不能为空.
*
* @param dispatcher 调度程序分配器
* @return 构造器
*/
public Builder dispatcher(Dispatcher dispatcher) {
if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null");
this.dispatcher = dispatcher;
return this;
}
/**
* 配置此客户端使用的协议以与远程服务器通信。默认情况下,该客户机将选择最有效的传输方式
* 退回到更普遍的协议。应用程序应该只调用这个方法来避免特定的兼容性问题,比如在启用HTTP/2时web服务器的行为不正确.
*
* @param protocols 使用的协议,按优先顺序排列。如果列表包含{@link Protocol#H2_PRIOR_KNOWLEDGE},
* 那么它必须是唯一的协议,并且不支持HTTPS url。否则列表必须包含{@link Protocol#HTTP_1_1}。
* 该列表不能包含null或{@link Protocol#HTTP_1_0}.
* @return 构造器
*/
public Builder protocols(List protocols) {
// 创建列表的私有副本
protocols = new ArrayList<>(protocols);
// 验证该列表包含我们需要的所有内容,没有我们禁止的内容.
if (!protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE)
&& !protocols.contains(Protocol.HTTP_1_1)) {
throw new IllegalArgumentException(
"protocols must contain h2_prior_knowledge or http/1.1: " + protocols);
}
if (protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE) && protocols.size() > 1) {
throw new IllegalArgumentException(
"protocols containing h2_prior_knowledge cannot use other protocols: " + protocols);
}
if (protocols.contains(Protocol.HTTP_1_0)) {
throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols);
}
if (protocols.contains(null)) {
throw new IllegalArgumentException("protocols must not contain null");
}
// 删除不再支持的协议
protocols.remove(Protocol.SPDY_3);
// 指定为不可修改的列表。这是有效不可变的.
this.protocols = Collections.unmodifiableList(protocols);
return this;
}
public Builder connectionSpecs(List connectionSuites) {
this.connectionSuites = org.aoju.bus.http.Builder.immutableList(connectionSuites);
return this;
}
/**
* 返回一个可修改的拦截器列表,该列表观察每个调用的完整跨度:
* 从建立连接之前(如果有的话)到选择响应源之后(源服务器、缓存或两者都有).
*
* @return 构造器
*/
public List interceptors() {
return interceptors;
}
public Builder addInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
interceptors.add(interceptor);
return this;
}
/**
* 返回观察单个网络请求和响应的可修改的拦截器列表。
* 这些拦截器必须调用{@link Interceptor.Chain#proceed}
* 只执行一次:网络拦截器短路或重复网络请求是错误的
*
* @return 构造器
*/
public List networkInterceptors() {
return networkInterceptors;
}
public Builder addNetworkInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
networkInterceptors.add(interceptor);
return this;
}
/**
* 配置单个客户机作用域侦听器,该侦听器将接收此客户机的所有分析事件.
*
* @param eventListener 监听器
* @return 构造器
*/
public Builder eventListener(EventListener eventListener) {
if (eventListener == null) throw new NullPointerException("eventListener == null");
this.eventListenerFactory = EventListener.factory(eventListener);
return this;
}
/**
* 配置工厂以提供每个调用范围的侦听器,这些侦听器将接收此客户机的分析事件
*
* @param eventListenerFactory 监听工厂信息
* @return 构造器
*/
public Builder eventListenerFactory(EventListener.Factory eventListenerFactory) {
if (eventListenerFactory == null) {
throw new NullPointerException("eventListenerFactory == null");
}
this.eventListenerFactory = eventListenerFactory;
return this;
}
public Httpd build() {
return new Httpd(this);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy