¶Ô±ÈÐÂÎļþ |
| | |
| | | /* |
| | | * Copyright (c) 2018-2028, DreamLu All rights reserved. |
| | | * |
| | | * Redistribution and use in source and binary forms, with or without |
| | | * modification, are permitted provided that the following conditions are met: |
| | | * |
| | | * Redistributions of source code must retain the above copyright notice, |
| | | * this list of conditions and the following disclaimer. |
| | | * Redistributions in binary form must reproduce the above copyright |
| | | * notice, this list of conditions and the following disclaimer in the |
| | | * documentation and/or other materials provided with the distribution. |
| | | * Neither the name of the dreamlu.net developer nor the names of its |
| | | * contributors may be used to endorse or promote products derived from |
| | | * this software without specific prior written permission. |
| | | * Author: DreamLu 墿¥æ¢¦ (596392912@qq.com) |
| | | */ |
| | | package org.springblade.core.http; |
| | | |
| | | import okhttp3.*; |
| | | import okhttp3.internal.Util; |
| | | import okhttp3.internal.http.HttpMethod; |
| | | import okhttp3.logging.HttpLoggingInterceptor; |
| | | import org.springblade.core.tool.jackson.JsonUtil; |
| | | import org.springblade.core.tool.ssl.DisableValidationTrustManager; |
| | | import org.springblade.core.tool.ssl.TrustAllHostNames; |
| | | import org.springblade.core.tool.utils.Exceptions; |
| | | import org.springblade.core.tool.utils.Holder; |
| | | import org.springblade.core.tool.utils.StringPool; |
| | | |
| | | import javax.annotation.Nonnull; |
| | | import javax.annotation.Nullable; |
| | | import javax.net.ssl.*; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.Proxy; |
| | | import java.net.ProxySelector; |
| | | import java.net.URI; |
| | | import java.security.KeyManagementException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.time.Duration; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.function.Predicate; |
| | | |
| | | /** |
| | | * ok http å°è£
ï¼è¯·æ±ç»æä½ |
| | | * |
| | | * @author L.cm |
| | | */ |
| | | public class HttpRequest { |
| | | 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"; |
| | | private static final MediaType APPLICATION_JSON = MediaType.parse("application/json;charset=UTF-8"); |
| | | private static volatile OkHttpClient httpClient = new OkHttpClient(); |
| | | @Nullable |
| | | private static HttpLoggingInterceptor globalLoggingInterceptor = null; |
| | | private final Request.Builder requestBuilder; |
| | | private final HttpUrl.Builder uriBuilder; |
| | | private final String httpMethod; |
| | | private String userAgent; |
| | | @Nullable |
| | | private RequestBody requestBody; |
| | | @Nullable |
| | | private Boolean followRedirects; |
| | | @Nullable |
| | | private Boolean followSslRedirects; |
| | | @Nullable |
| | | private HttpLoggingInterceptor.Level level; |
| | | @Nullable |
| | | private CookieJar cookieJar; |
| | | @Nullable |
| | | private EventListener eventListener; |
| | | private final List<Interceptor> interceptors = new ArrayList<>(); |
| | | @Nullable |
| | | private Authenticator authenticator; |
| | | @Nullable |
| | | private Duration connectTimeout; |
| | | @Nullable |
| | | private Duration readTimeout; |
| | | @Nullable |
| | | private Duration writeTimeout; |
| | | @Nullable |
| | | private Proxy proxy; |
| | | @Nullable |
| | | private ProxySelector proxySelector; |
| | | @Nullable |
| | | private Authenticator proxyAuthenticator; |
| | | @Nullable |
| | | private RetryPolicy retryPolicy; |
| | | @Nullable |
| | | private Boolean disableSslValidation; |
| | | @Nullable |
| | | private HostnameVerifier hostnameVerifier; |
| | | @Nullable |
| | | private SSLSocketFactory sslSocketFactory; |
| | | @Nullable |
| | | private X509TrustManager trustManager; |
| | | |
| | | public static HttpRequest get(final String url) { |
| | | return new HttpRequest(new Request.Builder(), url, Method.GET); |
| | | } |
| | | |
| | | public static HttpRequest get(final URI uri) { |
| | | return get(uri.toString()); |
| | | } |
| | | |
| | | public static HttpRequest post(final String url) { |
| | | return new HttpRequest(new Request.Builder(), url, Method.POST); |
| | | } |
| | | |
| | | public static HttpRequest post(final URI uri) { |
| | | return post(uri.toString()); |
| | | } |
| | | |
| | | public static HttpRequest patch(final String url) { |
| | | return new HttpRequest(new Request.Builder(), url, Method.PATCH); |
| | | } |
| | | |
| | | public static HttpRequest patch(final URI uri) { |
| | | return patch(uri.toString()); |
| | | } |
| | | |
| | | public static HttpRequest put(final String url) { |
| | | return new HttpRequest(new Request.Builder(), url, Method.PUT); |
| | | } |
| | | |
| | | public static HttpRequest put(final URI uri) { |
| | | return put(uri.toString()); |
| | | } |
| | | |
| | | public static HttpRequest delete(final String url) { |
| | | return new HttpRequest(new Request.Builder(), url, Method.DELETE); |
| | | } |
| | | |
| | | public static HttpRequest delete(final URI uri) { |
| | | return delete(uri.toString()); |
| | | } |
| | | |
| | | public HttpRequest query(String query) { |
| | | this.uriBuilder.query(query); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest queryEncoded(String encodedQuery) { |
| | | this.uriBuilder.encodedQuery(encodedQuery); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest queryMap(@Nullable Map<String, Object> queryMap) { |
| | | if (queryMap != null && !queryMap.isEmpty()) { |
| | | queryMap.forEach(this::query); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest query(String name, @Nullable Object value) { |
| | | this.uriBuilder.addQueryParameter(name, value == null ? null : String.valueOf(value)); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest queryEncoded(String encodedName, @Nullable Object encodedValue) { |
| | | this.uriBuilder.addEncodedQueryParameter(encodedName, encodedValue == null ? null : String.valueOf(encodedValue)); |
| | | return this; |
| | | } |
| | | |
| | | HttpRequest form(FormBody formBody) { |
| | | this.requestBody = formBody; |
| | | return this; |
| | | } |
| | | |
| | | HttpRequest multipartForm(MultipartBody multipartBody) { |
| | | this.requestBody = multipartBody; |
| | | return this; |
| | | } |
| | | |
| | | public FormBuilder formBuilder() { |
| | | return new FormBuilder(this); |
| | | } |
| | | |
| | | public MultipartFormBuilder multipartFormBuilder() { |
| | | return new MultipartFormBuilder(this); |
| | | } |
| | | |
| | | public HttpRequest body(RequestBody requestBody) { |
| | | this.requestBody = requestBody; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest bodyString(String body) { |
| | | this.requestBody = RequestBody.create(APPLICATION_JSON, body); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest bodyString(MediaType contentType, String body) { |
| | | this.requestBody = RequestBody.create(contentType, body); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest bodyJson(@Nonnull Object body) { |
| | | return bodyString(JsonUtil.toJson(body)); |
| | | } |
| | | |
| | | private HttpRequest(final Request.Builder requestBuilder, String url, String httpMethod) { |
| | | HttpUrl httpUrl = HttpUrl.parse(url); |
| | | if (httpUrl == null) { |
| | | throw new IllegalArgumentException(String.format("Url ä¸è½è§£æ: %s: [%s]ã", httpMethod.toLowerCase(), url)); |
| | | } |
| | | this.requestBuilder = requestBuilder; |
| | | this.uriBuilder = httpUrl.newBuilder(); |
| | | this.httpMethod = httpMethod; |
| | | this.userAgent = DEFAULT_USER_AGENT; |
| | | } |
| | | |
| | | private Call internalCall(final OkHttpClient client) { |
| | | OkHttpClient.Builder builder = client.newBuilder(); |
| | | if (connectTimeout != null) { |
| | | builder.connectTimeout(connectTimeout.toMillis(), TimeUnit.MILLISECONDS); |
| | | } |
| | | if (readTimeout != null) { |
| | | builder.readTimeout(readTimeout.toMillis(), TimeUnit.MILLISECONDS); |
| | | } |
| | | if (writeTimeout != null) { |
| | | builder.writeTimeout(writeTimeout.toMillis(), TimeUnit.MILLISECONDS); |
| | | } |
| | | if (proxy != null) { |
| | | builder.proxy(proxy); |
| | | } |
| | | if (proxySelector != null) { |
| | | builder.proxySelector(proxySelector); |
| | | } |
| | | if (proxyAuthenticator != null) { |
| | | builder.proxyAuthenticator(proxyAuthenticator); |
| | | } |
| | | if (hostnameVerifier != null) { |
| | | builder.hostnameVerifier(hostnameVerifier); |
| | | } |
| | | if (sslSocketFactory != null && trustManager != null) { |
| | | builder.sslSocketFactory(sslSocketFactory, trustManager); |
| | | } |
| | | if (Boolean.TRUE.equals(disableSslValidation)) { |
| | | disableSslValidation(builder); |
| | | } |
| | | if (authenticator != null) { |
| | | builder.authenticator(authenticator); |
| | | } |
| | | if (!interceptors.isEmpty()) { |
| | | builder.interceptors().addAll(interceptors); |
| | | } |
| | | if (cookieJar != null) { |
| | | builder.cookieJar(cookieJar); |
| | | } |
| | | if (eventListener != null) { |
| | | builder.eventListener(eventListener); |
| | | } |
| | | if (followRedirects != null) { |
| | | builder.followRedirects(followRedirects); |
| | | } |
| | | if (followSslRedirects != null) { |
| | | builder.followSslRedirects(followSslRedirects); |
| | | } |
| | | if (retryPolicy != null) { |
| | | builder.addInterceptor(new RetryInterceptor(retryPolicy)); |
| | | } |
| | | if (level != null && HttpLoggingInterceptor.Level.NONE != level) { |
| | | builder.addInterceptor(getLoggingInterceptor(level)); |
| | | } else if (globalLoggingInterceptor != null) { |
| | | builder.addInterceptor(globalLoggingInterceptor); |
| | | } |
| | | // 设置 User-Agent |
| | | requestBuilder.header("User-Agent", userAgent); |
| | | // url |
| | | requestBuilder.url(uriBuilder.build()); |
| | | String method = httpMethod; |
| | | Request request; |
| | | if (HttpMethod.requiresRequestBody(method) && requestBody == null) { |
| | | request = requestBuilder.method(method, Util.EMPTY_REQUEST).build(); |
| | | } else { |
| | | request = requestBuilder.method(method, requestBody).build(); |
| | | } |
| | | return builder.build().newCall(request); |
| | | } |
| | | |
| | | public Exchange execute() { |
| | | return new Exchange(internalCall(httpClient)); |
| | | } |
| | | |
| | | public AsyncCall async() { |
| | | return new AsyncCall(internalCall(httpClient)); |
| | | } |
| | | |
| | | public HttpRequest baseAuth(String userName, String password) { |
| | | this.authenticator = new BaseAuthenticator(userName, password); |
| | | return this; |
| | | } |
| | | |
| | | //// HTTP header operations |
| | | public HttpRequest addHeader(final Map<String, String> headers) { |
| | | this.requestBuilder.headers(Headers.of(headers)); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest addHeader(final String... namesAndValues) { |
| | | Headers headers = Headers.of(namesAndValues); |
| | | this.requestBuilder.headers(headers); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest addHeader(final String name, final String value) { |
| | | this.requestBuilder.addHeader(name, value); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest setHeader(final String name, final String value) { |
| | | this.requestBuilder.header(name, value); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest removeHeader(final String name) { |
| | | this.requestBuilder.removeHeader(name); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest addCookie(final Cookie cookie) { |
| | | this.addHeader("Cookie", cookie.toString()); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest cacheControl(final CacheControl cacheControl) { |
| | | this.requestBuilder.cacheControl(cacheControl); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest userAgent(final String userAgent) { |
| | | this.userAgent = userAgent; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest followRedirects(boolean followRedirects) { |
| | | this.followRedirects = followRedirects; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest followSslRedirects(boolean followSslRedirects) { |
| | | this.followSslRedirects = followSslRedirects; |
| | | return this; |
| | | } |
| | | |
| | | private static HttpLoggingInterceptor getLoggingInterceptor(HttpLoggingInterceptor.Level level) { |
| | | HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(Slf4jLogger.INSTANCE); |
| | | loggingInterceptor.setLevel(level); |
| | | return loggingInterceptor; |
| | | } |
| | | |
| | | public HttpRequest log() { |
| | | this.level = HttpLoggingInterceptor.Level.BODY; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest log(LogLevel logLevel) { |
| | | this.level = logLevel.getLevel(); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest authenticator(Authenticator authenticator) { |
| | | this.authenticator = authenticator; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest interceptor(Interceptor interceptor) { |
| | | this.interceptors.add(interceptor); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest cookieManager(CookieJar cookieJar) { |
| | | this.cookieJar = cookieJar; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest eventListener(EventListener eventListener) { |
| | | this.eventListener = eventListener; |
| | | return this; |
| | | } |
| | | |
| | | //// HTTP connection parameter operations |
| | | public HttpRequest connectTimeout(final Duration timeout) { |
| | | this.connectTimeout = timeout; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest readTimeout(Duration readTimeout) { |
| | | this.readTimeout = readTimeout; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest writeTimeout(Duration writeTimeout) { |
| | | this.writeTimeout = writeTimeout; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest proxy(final InetSocketAddress address) { |
| | | this.proxy = new Proxy(Proxy.Type.HTTP, address); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest proxySelector(final ProxySelector proxySelector) { |
| | | this.proxySelector = proxySelector; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest proxyAuthenticator(final Authenticator proxyAuthenticator) { |
| | | this.proxyAuthenticator = proxyAuthenticator; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest retry() { |
| | | this.retryPolicy = RetryPolicy.INSTANCE; |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest retryOn(Predicate<ResponseSpec> respPredicate) { |
| | | this.retryPolicy = new RetryPolicy(respPredicate); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest retry(int maxAttempts, long sleepMillis) { |
| | | this.retryPolicy = new RetryPolicy(maxAttempts, sleepMillis); |
| | | return this; |
| | | } |
| | | |
| | | public HttpRequest retry(int maxAttempts, long sleepMillis, Predicate<ResponseSpec> respPredicate) { |
| | | this.retryPolicy = new RetryPolicy(maxAttempts, sleepMillis); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * å
³é ssl æ ¡éª |
| | | * |
| | | * @return HttpRequest |
| | | */ |
| | | public HttpRequest disableSslValidation() { |
| | | this.disableSslValidation = Boolean.TRUE; |
| | | return this; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return requestBuilder.toString(); |
| | | } |
| | | |
| | | public static void setHttpClient(OkHttpClient httpClient) { |
| | | HttpRequest.httpClient = httpClient; |
| | | } |
| | | |
| | | public static void setGlobalLog(LogLevel logLevel) { |
| | | HttpRequest.globalLoggingInterceptor = getLoggingInterceptor(logLevel.getLevel()); |
| | | } |
| | | |
| | | static String handleValue(@Nullable Object value) { |
| | | if (value == null) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | if (value instanceof String) { |
| | | return (String) value; |
| | | } |
| | | return String.valueOf(value); |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | } |