HttpRequest.java 14.1 KB
Newer Older
如梦技术's avatar
如梦技术 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2019-2029, Dreamlu (596392912@qq.com & www.dreamlu.net).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17
package net.dreamlu.mica.http;
如梦技术's avatar
如梦技术 已提交
18

如梦技术's avatar
如梦技术 已提交
19 20 21 22
import net.dreamlu.mica.core.ssl.DisableValidationTrustManager;
import net.dreamlu.mica.core.ssl.TrustAllHostNames;
import net.dreamlu.mica.core.utils.Exceptions;
import net.dreamlu.mica.core.utils.Holder;
如梦技术's avatar
如梦技术 已提交
23
import net.dreamlu.mica.core.utils.JsonUtil;
如梦技术's avatar
如梦技术 已提交
24
import net.dreamlu.mica.core.utils.StringPool;
如梦技术's avatar
如梦技术 已提交
25
import okhttp3.*;
26
import okhttp3.internal.Util;
如梦技术's avatar
如梦技术 已提交
27 28 29
import okhttp3.internal.http.HttpMethod;
import okhttp3.logging.HttpLoggingInterceptor;

30
import javax.annotation.Nullable;
如梦技术's avatar
如梦技术 已提交
31
import javax.net.ssl.*;
如梦技术's avatar
如梦技术 已提交
32
import java.io.IOException;
如梦技术's avatar
如梦技术 已提交
33
import java.net.InetSocketAddress;
如梦技术's avatar
如梦技术 已提交
34
import java.net.Proxy;
如梦技术's avatar
如梦技术 已提交
35
import java.net.ProxySelector;
如梦技术's avatar
如梦技术 已提交
36
import java.net.URI;
如梦技术's avatar
如梦技术 已提交
37 38
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
如梦技术's avatar
如梦技术 已提交
39
import java.time.Duration;
40 41
import java.util.ArrayList;
import java.util.List;
42
import java.util.Map;
如梦技术's avatar
如梦技术 已提交
43
import java.util.concurrent.TimeUnit;
44 45 46
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
47
import java.util.function.Predicate;
如梦技术's avatar
如梦技术 已提交
48 49 50 51 52 53

/**
 * ok http 封装,请求结构体
 *
 * @author L.cm
 */
54
public class HttpRequest {
如梦技术's avatar
如梦技术 已提交
55
	private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36";
如梦技术's avatar
如梦技术 已提交
56
	private static volatile OkHttpClient httpClient = new OkHttpClient();
57
	@Nullable
58
	private static HttpLoggingInterceptor globalLoggingInterceptor = null;
如梦技术's avatar
如梦技术 已提交
59
	private final Request.Builder requestBuilder;
60
	private final HttpUrl.Builder uriBuilder;
如梦技术's avatar
如梦技术 已提交
61 62
	private final String httpMethod;
	private String userAgent;
63
	@Nullable
如梦技术's avatar
如梦技术 已提交
64
	private RequestBody requestBody;
65
	@Nullable
如梦技术's avatar
如梦技术 已提交
66
	private Boolean followRedirects;
67
	@Nullable
68
	private Boolean followSslRedirects;
69
	@Nullable
如梦技术's avatar
如梦技术 已提交
70
	private HttpLoggingInterceptor.Level level;
71
	@Nullable
72
	private CookieJar cookieJar;
73
	@Nullable
74
	private EventListener eventListener;
75
	private final List<Interceptor> interceptors = new ArrayList<>();
76
	@Nullable
77
	private Authenticator authenticator;
78
	@Nullable
如梦技术's avatar
如梦技术 已提交
79
	private Duration connectTimeout;
80
	@Nullable
如梦技术's avatar
如梦技术 已提交
81
	private Duration readTimeout;
82
	@Nullable
如梦技术's avatar
如梦技术 已提交
83
	private Duration writeTimeout;
84
	@Nullable
如梦技术's avatar
如梦技术 已提交
85
	private Proxy proxy;
86
	@Nullable
如梦技术's avatar
如梦技术 已提交
87
	private ProxySelector proxySelector;
88
	@Nullable
如梦技术's avatar
如梦技术 已提交
89
	private Authenticator proxyAuthenticator;
90 91 92
	@Nullable
	private RetryPolicy retryPolicy;
	@Nullable
如梦技术's avatar
如梦技术 已提交
93 94
	private Boolean disableSslValidation;
	@Nullable
如梦技术's avatar
如梦技术 已提交
95
	private HostnameVerifier hostnameVerifier;
96
	@Nullable
如梦技术's avatar
如梦技术 已提交
97
	private SSLSocketFactory sslSocketFactory;
98
	@Nullable
如梦技术's avatar
如梦技术 已提交
99
	private X509TrustManager trustManager;
如梦技术's avatar
如梦技术 已提交
100

101
	public static HttpRequest get(final String url) {
如梦技术's avatar
如梦技术 已提交
102
		return new HttpRequest(new Request.Builder(), url, Method.GET);
如梦技术's avatar
如梦技术 已提交
103 104
	}

105
	public static HttpRequest get(final URI uri) {
如梦技术's avatar
如梦技术 已提交
106
		return get(uri.toString());
如梦技术's avatar
如梦技术 已提交
107 108
	}

109
	public static HttpRequest post(final String url) {
如梦技术's avatar
如梦技术 已提交
110
		return new HttpRequest(new Request.Builder(), url, Method.POST);
如梦技术's avatar
如梦技术 已提交
111 112
	}

113
	public static HttpRequest post(final URI uri) {
如梦技术's avatar
如梦技术 已提交
114
		return post(uri.toString());
如梦技术's avatar
如梦技术 已提交
115 116
	}

117
	public static HttpRequest patch(final String url) {
如梦技术's avatar
如梦技术 已提交
118
		return new HttpRequest(new Request.Builder(), url, Method.PATCH);
如梦技术's avatar
如梦技术 已提交
119 120
	}

121
	public static HttpRequest patch(final URI uri) {
如梦技术's avatar
如梦技术 已提交
122
		return patch(uri.toString());
如梦技术's avatar
如梦技术 已提交
123 124
	}

125
	public static HttpRequest put(final String url) {
如梦技术's avatar
如梦技术 已提交
126
		return new HttpRequest(new Request.Builder(), url, Method.PUT);
如梦技术's avatar
如梦技术 已提交
127 128
	}

129
	public static HttpRequest put(final URI uri) {
如梦技术's avatar
如梦技术 已提交
130
		return put(uri.toString());
如梦技术's avatar
如梦技术 已提交
131 132
	}

133
	public static HttpRequest delete(final String url) {
如梦技术's avatar
如梦技术 已提交
134
		return new HttpRequest(new Request.Builder(), url, Method.DELETE);
如梦技术's avatar
如梦技术 已提交
135 136
	}

137
	public static HttpRequest delete(final URI uri) {
如梦技术's avatar
如梦技术 已提交
138
		return delete(uri.toString());
如梦技术's avatar
如梦技术 已提交
139 140
	}

141 142
	public HttpRequest query(String query) {
		this.uriBuilder.query(query);
如梦技术's avatar
如梦技术 已提交
143 144 145
		return this;
	}

如梦技术's avatar
如梦技术 已提交
146
	public HttpRequest queryEncoded(String encodedQuery) {
147 148 149 150
		this.uriBuilder.encodedQuery(encodedQuery);
		return this;
	}

151
	public HttpRequest queryMap(@Nullable Map<String, Object> queryMap) {
152 153 154 155 156 157
		if (queryMap != null && !queryMap.isEmpty()) {
			queryMap.forEach(this::query);
		}
		return this;
	}

如梦技术's avatar
如梦技术 已提交
158
	public HttpRequest query(String name, @Nullable Object value) {
159 160 161 162
		this.uriBuilder.addQueryParameter(name, value == null ? null : String.valueOf(value));
		return this;
	}

如梦技术's avatar
如梦技术 已提交
163 164
	public HttpRequest queryEncoded(String encodedName, @Nullable Object encodedValue) {
		this.uriBuilder.addEncodedQueryParameter(encodedName, encodedValue == null ? null : String.valueOf(encodedValue));
如梦技术's avatar
如梦技术 已提交
165 166 167
		return this;
	}

168
	HttpRequest form(FormBody formBody) {
如梦技术's avatar
如梦技术 已提交
169 170 171 172
		this.requestBody = formBody;
		return this;
	}

173
	HttpRequest multipartForm(MultipartBody multipartBody) {
如梦技术's avatar
如梦技术 已提交
174 175 176 177
		this.requestBody = multipartBody;
		return this;
	}

178 179
	public FormBuilder formBuilder() {
		return new FormBuilder(this);
如梦技术's avatar
如梦技术 已提交
180 181
	}

182 183
	public MultipartFormBuilder multipartFormBuilder() {
		return new MultipartFormBuilder(this);
如梦技术's avatar
如梦技术 已提交
184 185
	}

186
	public HttpRequest body(RequestBody requestBody) {
如梦技术's avatar
如梦技术 已提交
187 188 189 190
		this.requestBody = requestBody;
		return this;
	}

191
	public HttpRequest bodyString(String body) {
如梦技术's avatar
如梦技术 已提交
192 193 194 195
		this.requestBody = RequestBody.create(null, body);
		return this;
	}

196
	public HttpRequest bodyJson(Object body) {
如梦技术's avatar
如梦技术 已提交
197 198 199
		return bodyString(JsonUtil.toJson(body));
	}

如梦技术's avatar
如梦技术 已提交
200 201
	private HttpRequest(final Request.Builder requestBuilder, String url, String httpMethod) {
		HttpUrl httpUrl = HttpUrl.parse(url);
202 203 204
		if (httpUrl == null) {
			throw new IllegalArgumentException(String.format("Url 不能解析: %s: [%s]。", httpMethod.toLowerCase(), url));
		}
如梦技术's avatar
如梦技术 已提交
205
		this.requestBuilder = requestBuilder;
206
		this.uriBuilder = httpUrl.newBuilder();
如梦技术's avatar
如梦技术 已提交
207 208 209 210
		this.httpMethod = httpMethod;
		this.userAgent = DEFAULT_USER_AGENT;
	}

211
	private Call internalCall(final OkHttpClient client) {
如梦技术's avatar
如梦技术 已提交
212
		OkHttpClient.Builder builder = client.newBuilder();
213 214
		if (connectTimeout != null) {
			builder.connectTimeout(connectTimeout.toMillis(), TimeUnit.MILLISECONDS);
如梦技术's avatar
如梦技术 已提交
215
		}
216 217
		if (readTimeout != null) {
			builder.readTimeout(readTimeout.toMillis(), TimeUnit.MILLISECONDS);
如梦技术's avatar
如梦技术 已提交
218
		}
219 220
		if (writeTimeout != null) {
			builder.writeTimeout(writeTimeout.toMillis(), TimeUnit.MILLISECONDS);
如梦技术's avatar
如梦技术 已提交
221
		}
222 223
		if (proxy != null) {
			builder.proxy(proxy);
如梦技术's avatar
如梦技术 已提交
224
		}
225 226
		if (proxySelector != null) {
			builder.proxySelector(proxySelector);
如梦技术's avatar
如梦技术 已提交
227
		}
228
		if (proxyAuthenticator != null) {
如梦技术's avatar
如梦技术 已提交
229 230
			builder.proxyAuthenticator(proxyAuthenticator);
		}
231
		if (hostnameVerifier != null) {
如梦技术's avatar
如梦技术 已提交
232 233
			builder.hostnameVerifier(hostnameVerifier);
		}
234
		if (sslSocketFactory != null && trustManager != null) {
如梦技术's avatar
如梦技术 已提交
235 236
			builder.sslSocketFactory(sslSocketFactory, trustManager);
		}
如梦技术's avatar
如梦技术 已提交
237 238 239
		if (Boolean.TRUE.equals(disableSslValidation)) {
			disableSslValidation(builder);
		}
240
		if (authenticator != null) {
241 242
			builder.authenticator(authenticator);
		}
243 244
		if (eventListener != null) {
			builder.eventListener(eventListener);
如梦技术's avatar
如梦技术 已提交
245
		}
246 247 248 249
		if (!interceptors.isEmpty()) {
			builder.interceptors().addAll(interceptors);
		}
		if (cookieJar != null) {
250 251
			builder.cookieJar(cookieJar);
		}
252 253
		if (followRedirects != null) {
			builder.followRedirects(followRedirects);
254
		}
255 256
		if (followSslRedirects != null) {
			builder.followSslRedirects(followSslRedirects);
如梦技术's avatar
如梦技术 已提交
257
		}
258 259 260
		if (retryPolicy != null) {
			builder.addInterceptor(new RetryInterceptor(retryPolicy));
		}
261
		if (level != null && HttpLoggingInterceptor.Level.NONE != level) {
262 263 264 265
			builder.addInterceptor(getLoggingInterceptor(level));
		} else if (globalLoggingInterceptor != null) {
			builder.addInterceptor(globalLoggingInterceptor);
		}
如梦技术's avatar
如梦技术 已提交
266
		// 设置 User-Agent
267
		requestBuilder.header("User-Agent", userAgent);
如梦技术's avatar
如梦技术 已提交
268
		// url
269
		requestBuilder.url(uriBuilder.build());
270
		String method = httpMethod;
如梦技术's avatar
如梦技术 已提交
271 272
		Request request;
		if (HttpMethod.requiresRequestBody(method) && requestBody == null) {
273
			request = requestBuilder.method(method, Util.EMPTY_REQUEST).build();
如梦技术's avatar
如梦技术 已提交
274
		} else {
275
			request = requestBuilder.method(method, requestBody).build();
如梦技术's avatar
如梦技术 已提交
276
		}
277
		return builder.build().newCall(request);
如梦技术's avatar
如梦技术 已提交
278 279
	}

280
	public <R> R onResponse(Function<ResponseSpec, R> func) {
281
		Call call = internalCall(httpClient);
282 283
		try (HttpResponse response = new HttpResponse(call.execute())) {
			return func.apply(response);
如梦技术's avatar
如梦技术 已提交
284
		} catch (IOException e) {
285 286 287 288 289 290 291 292 293 294 295
			return func.apply(new ErrorResponse(call.request(), e));
		}
	}

	@Nullable
	public <R> R onSuccess(Function<ResponseSpec, R> func) {
		Call call = internalCall(httpClient);
		try (HttpResponse response = new HttpResponse(call.execute())) {
			return func.apply(response);
		} catch (IOException ignore) {
			return null;
如梦技术's avatar
如梦技术 已提交
296 297 298
		}
	}

299 300 301 302 303
	public AsyncCall async() {
		Call call = internalCall(httpClient);
		return new AsyncCall(call);
	}

304 305 306 307 308
	public HttpRequest baseAuth(String userName, String password) {
		this.authenticator = new BaseAuthenticator(userName, password);
		return this;
	}

如梦技术's avatar
如梦技术 已提交
309
	//// HTTP header operations
310 311 312 313 314 315
	public HttpRequest addHeader(final Map<String, String> headers) {
		this.requestBuilder.headers(Headers.of(headers));
		return this;
	}

	public HttpRequest addHeader(final String... namesAndValues) {
如梦技术's avatar
如梦技术 已提交
316 317 318 319 320
		Headers headers = Headers.of(namesAndValues);
		this.requestBuilder.headers(headers);
		return this;
	}

321
	public HttpRequest addHeader(final String name, final String value) {
如梦技术's avatar
如梦技术 已提交
322 323 324 325
		this.requestBuilder.addHeader(name, value);
		return this;
	}

326
	public HttpRequest setHeader(final String name, final String value) {
如梦技术's avatar
如梦技术 已提交
327 328 329 330
		this.requestBuilder.header(name, value);
		return this;
	}

331
	public HttpRequest removeHeader(final String name) {
如梦技术's avatar
如梦技术 已提交
332 333 334 335
		this.requestBuilder.removeHeader(name);
		return this;
	}

336 337 338 339 340
	public HttpRequest addCookie(final Cookie cookie) {
		this.addHeader("Cookie", cookie.toString());
		return this;
	}

341
	public HttpRequest cacheControl(final CacheControl cacheControl) {
如梦技术's avatar
如梦技术 已提交
342 343 344 345
		this.requestBuilder.cacheControl(cacheControl);
		return this;
	}

346
	public HttpRequest userAgent(final String userAgent) {
如梦技术's avatar
如梦技术 已提交
347 348 349 350
		this.userAgent = userAgent;
		return this;
	}

351
	public HttpRequest followRedirects(boolean followRedirects) {
如梦技术's avatar
如梦技术 已提交
352 353 354 355
		this.followRedirects = followRedirects;
		return this;
	}

356 357 358 359 360
	public HttpRequest followSslRedirects(boolean followSslRedirects) {
		this.followSslRedirects = followSslRedirects;
		return this;
	}

如梦技术's avatar
如梦技术 已提交
361 362 363 364 365 366
	private static HttpLoggingInterceptor getLoggingInterceptor(HttpLoggingInterceptor.Level level) {
		HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(Slf4jLogger.INSTANCE);
		loggingInterceptor.setLevel(level);
		return loggingInterceptor;
	}

367
	public HttpRequest log() {
如梦技术's avatar
如梦技术 已提交
368 369 370 371
		this.level = HttpLoggingInterceptor.Level.BODY;
		return this;
	}

如梦技术's avatar
如梦技术 已提交
372 373
	public HttpRequest log(LogLevel logLevel) {
		this.level = logLevel.getLevel();
如梦技术's avatar
如梦技术 已提交
374 375 376
		return this;
	}

377 378 379 380 381
	public HttpRequest authenticator(Authenticator authenticator) {
		this.authenticator = authenticator;
		return this;
	}

382 383 384 385 386
	public HttpRequest eventListener(EventListener eventListener) {
		this.eventListener = eventListener;
		return this;
	}

387
	public HttpRequest interceptor(Interceptor interceptor) {
388
		this.interceptors.add(interceptor);
如梦技术's avatar
如梦技术 已提交
389 390 391
		return this;
	}

392 393 394 395 396
	public HttpRequest cookieManager(CookieJar cookieJar) {
		this.cookieJar = cookieJar;
		return this;
	}

如梦技术's avatar
如梦技术 已提交
397
	//// HTTP connection parameter operations
398
	public HttpRequest connectTimeout(final Duration timeout) {
如梦技术's avatar
如梦技术 已提交
399 400 401 402
		this.connectTimeout = timeout;
		return this;
	}

403
	public HttpRequest readTimeout(Duration readTimeout) {
如梦技术's avatar
如梦技术 已提交
404 405 406 407
		this.readTimeout = readTimeout;
		return this;
	}

408
	public HttpRequest writeTimeout(Duration writeTimeout) {
如梦技术's avatar
如梦技术 已提交
409 410 411 412
		this.writeTimeout = writeTimeout;
		return this;
	}

如梦技术's avatar
如梦技术 已提交
413
	public HttpRequest proxy(final InetSocketAddress address) {
如梦技术's avatar
如梦技术 已提交
414
		this.proxy = new Proxy(Proxy.Type.HTTP, address);
如梦技术's avatar
如梦技术 已提交
415 416 417
		return this;
	}

如梦技术's avatar
如梦技术 已提交
418 419 420 421 422 423 424 425 426 427
	public HttpRequest proxySelector(final ProxySelector proxySelector) {
		this.proxySelector = proxySelector;
		return this;
	}

	public HttpRequest proxyAuthenticator(final Authenticator proxyAuthenticator) {
		this.proxyAuthenticator = proxyAuthenticator;
		return this;
	}

428 429 430 431 432
	public HttpRequest retry() {
		this.retryPolicy = RetryPolicy.INSTANCE;
		return this;
	}

433 434 435 436 437
	public HttpRequest retryOn(Predicate<ResponseSpec> respPredicate) {
		this.retryPolicy = new RetryPolicy(respPredicate);
		return this;
	}

438 439 440 441 442
	public HttpRequest retry(int maxAttempts, long sleepMillis) {
		this.retryPolicy = new RetryPolicy(maxAttempts, sleepMillis);
		return this;
	}

443 444 445 446 447
	public HttpRequest retry(int maxAttempts, long sleepMillis, Predicate<ResponseSpec> respPredicate) {
		this.retryPolicy = new RetryPolicy(maxAttempts, sleepMillis);
		return this;
	}

如梦技术's avatar
如梦技术 已提交
448 449 450 451 452 453 454 455 456 457
	/**
	 * 关闭 ssl 校验
	 *
	 * @return HttpRequest
	 */
	public HttpRequest disableSslValidation() {
		this.disableSslValidation = Boolean.TRUE;
		return this;
	}

如梦技术's avatar
如梦技术 已提交
458 459 460 461 462 463 464 465 466 467 468
	public HttpRequest hostnameVerifier(HostnameVerifier hostnameVerifier) {
		this.hostnameVerifier = hostnameVerifier;
		return this;
	}

	public HttpRequest sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
		this.sslSocketFactory = sslSocketFactory;
		this.trustManager = trustManager;
		return this;
	}

如梦技术's avatar
如梦技术 已提交
469 470 471 472 473 474
	@Override
	public String toString() {
		return requestBuilder.toString();
	}

	public static void setHttpClient(OkHttpClient httpClient) {
475
		HttpRequest.httpClient = httpClient;
如梦技术's avatar
如梦技术 已提交
476
	}
如梦技术's avatar
如梦技术 已提交
477 478 479 480

	public static void setGlobalLog(LogLevel logLevel) {
		HttpRequest.globalLoggingInterceptor = getLoggingInterceptor(logLevel.getLevel());
	}
如梦技术's avatar
如梦技术 已提交
481 482 483 484 485 486 487 488 489 490

	static String handleValue(@Nullable Object value) {
		if (value == null) {
			return StringPool.EMPTY;
		}
		if (value instanceof String) {
			return (String) value;
		}
		return String.valueOf(value);
	}
如梦技术's avatar
如梦技术 已提交
491 492 493 494 495 496 497 498 499 500 501 502 503 504

	private static void disableSslValidation(OkHttpClient.Builder builder) {
		try {
			X509TrustManager disabledTrustManager = DisableValidationTrustManager.INSTANCE;
			TrustManager[] trustManagers = new TrustManager[]{disabledTrustManager};
			SSLContext sslContext = SSLContext.getInstance("SSL");
			sslContext.init(null, trustManagers, Holder.SECURE_RANDOM);
			SSLSocketFactory disabledSslSocketFactory = sslContext.getSocketFactory();
			builder.sslSocketFactory(disabledSslSocketFactory, disabledTrustManager);
			builder.hostnameVerifier(TrustAllHostNames.INSTANCE);
		} catch (NoSuchAlgorithmException | KeyManagementException e) {
			throw Exceptions.unchecked(e);
		}
	}
如梦技术's avatar
如梦技术 已提交
505
}