package com.zy.acs.manager.common.utils; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.time.Duration; import java.util.*; import java.util.concurrent.TimeUnit; /** * Minimal OkHttp wrapper: GET / POST only. * * - fluent API (get / postJson / postForm) * - default singleton instance (thread-safe) * - per-request headers + default headers * - simple response wrapper with tookMs * - optional trust-all SSL (ONLY for internal test) */ @Slf4j public final class HttpGo { private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private final OkHttpClient client; private final Map defaultHeaders; private HttpGo(OkHttpClient client, Map defaultHeaders) { this.client = Objects.requireNonNull(client, "client"); this.defaultHeaders = defaultHeaders == null ? Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap<>(defaultHeaders)); } /** Shared default instance (safe SSL by default). */ public static HttpGo defaults() { return Holder.DEFAULT; } public static Builder builder() { return new Builder(); } // ===================== GET ===================== public HttpResponse get(String url) throws IOException { return get(url, null, null); } public HttpResponse get(String url, Map queryParams) throws IOException { return get(url, null, queryParams); } public HttpResponse get(String url, Map headers, Map queryParams) throws IOException { HttpUrl parsed = HttpUrl.parse(url); if (parsed == null) throw new IllegalArgumentException("Invalid url: " + url); HttpUrl.Builder ub = parsed.newBuilder(); if (queryParams != null) { queryParams.forEach((k, v) -> { if (k != null && v != null) ub.addQueryParameter(k, v); }); } Request.Builder rb = new Request.Builder().url(ub.build()).get(); applyHeaders(rb, headers); return execute(rb.build()); } // ===================== POST ===================== /** POST JSON string payload (null/blank -> "{}"). */ public HttpResponse postJson(String url, String json) throws IOException { return postJson(url, null, json); } /** POST JSON string payload (null/blank -> "{}"). */ public HttpResponse postJson(String url, Map headers, String json) throws IOException { String payload = (json == null || json.trim().isEmpty()) ? "{}" : json; RequestBody body = RequestBody.create(payload, JSON); Request.Builder rb = new Request.Builder().url(url).post(body); applyHeaders(rb, headers); // ensure content-type unless caller overrides if (rb.build().header("Content-Type") == null) { rb.header("Content-Type", "application/json; charset=utf-8"); } return execute(rb.build()); } /** POST x-www-form-urlencoded fields. */ public HttpResponse postForm(String url, Map formFields) throws IOException { return postForm(url, null, formFields); } /** POST x-www-form-urlencoded fields. */ public HttpResponse postForm(String url, Map headers, Map formFields) throws IOException { FormBody.Builder fb = new FormBody.Builder(DEFAULT_CHARSET); if (formFields != null) { formFields.forEach((k, v) -> { if (k != null && v != null) fb.add(k, v); }); } Request.Builder rb = new Request.Builder().url(url).post(fb.build()); applyHeaders(rb, headers); return execute(rb.build()); } // ===================== Internals ===================== private HttpResponse execute(Request request) throws IOException { long start = System.nanoTime(); try (Response resp = client.newCall(request).execute()) { long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); String body = null; ResponseBody rb = resp.body(); if (rb != null) body = rb.string(); // one-shot return new HttpResponse(resp.code(), resp.headers(), body, tookMs); } catch (IOException e) { log.error("HttpGo request failed: {} {}", request.method(), request.url(), e); throw e; } } private void applyHeaders(Request.Builder rb, Map headers) { // defaults first, then per-request overrides if (defaultHeaders != null) { defaultHeaders.forEach((k, v) -> { if (k != null && v != null) rb.header(k, v); }); } if (headers != null) { headers.forEach((k, v) -> { if (k != null && v != null) rb.header(k, v); }); } } private static final class Holder { private static final HttpGo DEFAULT = HttpGo.builder().build(); } // ===================== Response ===================== public static final class HttpResponse { private final int statusCode; private final Headers headers; private final String body; private final long tookMs; public HttpResponse(int statusCode, Headers headers, String body, long tookMs) { this.statusCode = statusCode; this.headers = headers == null ? new Headers.Builder().build() : headers; this.body = body; this.tookMs = tookMs; } public int statusCode() { return statusCode; } public Headers headers() { return headers; } public String body() { return body; } public long tookMs() { return tookMs; } public boolean is2xx() { return statusCode >= 200 && statusCode < 300; } public String header(String name) { return headers.get(name); } @Override public String toString() { return "HttpResponse{status=" + statusCode + ", tookMs=" + tookMs + ", bodyLen=" + (body == null ? 0 : body.length()) + "}"; } } // ===================== Builder ===================== public static final class Builder { private Duration connectTimeout = Duration.ofSeconds(10); private Duration readTimeout = Duration.ofSeconds(20); private Duration writeTimeout = Duration.ofSeconds(20); private boolean trustAllSsl = false; private final Map defaultHeaders = new LinkedHashMap<>(); public Builder defaultHeader(String name, String value) { if (name != null && value != null) defaultHeaders.put(name, value); return this; } public Builder connectTimeout(Duration d) { if (d != null) connectTimeout = d; return this; } public Builder readTimeout(Duration d) { if (d != null) readTimeout = d; return this; } public Builder writeTimeout(Duration d) { if (d != null) writeTimeout = d; return this; } /** Trust ALL certificates. ONLY for internal testing/self-signed endpoints. */ public Builder trustAllSsl(boolean enable) { this.trustAllSsl = enable; return this; } public HttpGo build() { OkHttpClient.Builder cb = new OkHttpClient.Builder() .connectTimeout(connectTimeout.toMillis(), TimeUnit.MILLISECONDS) .readTimeout(readTimeout.toMillis(), TimeUnit.MILLISECONDS) .writeTimeout(writeTimeout.toMillis(), TimeUnit.MILLISECONDS); if (trustAllSsl) { TrustAll trustAll = new TrustAll(); cb.sslSocketFactory(trustAll.sslSocketFactory, trustAll.trustManager) .hostnameVerifier((hostname, session) -> true); } return new HttpGo(cb.build(), defaultHeaders); } } // ===================== Trust-all SSL helper ===================== private static final class TrustAll { final X509TrustManager trustManager; final SSLSocketFactory sslSocketFactory; TrustAll() { try { this.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, new TrustManager[]{trustManager}, new SecureRandom()); this.sslSocketFactory = sslContext.getSocketFactory(); } catch (Exception e) { throw new IllegalStateException("Failed to init trust-all SSL", e); } } } // ===================== Demo (main) ===================== public static void main(String[] args) throws Exception { HttpGo http = HttpGo.builder() .connectTimeout(Duration.ofSeconds(8)) .readTimeout(Duration.ofSeconds(15)) .defaultHeader("User-Agent", "HttpGo/1.0") // .trustAllSsl(true) // ONLY if you really need it .build(); // 1) GET with query params + per-request headers String getUrl = "https://httpbin.org/get"; Map query = new HashMap<>(); query.put("q", "vincent"); query.put("page", "1"); Map headers = new HashMap<>(); headers.put("X-Trace-Id", "trace-001"); HttpResponse r1 = http.get(getUrl, headers, query); System.out.println("GET status=" + r1.statusCode() + ", tookMs=" + r1.tookMs()); System.out.println(r1.body()); // 2) POST JSON String postUrl = "https://httpbin.org/post"; String json = "{\"name\":\"Vincent\",\"role\":\"engineer\"}"; Map postHeaders = new HashMap<>(); postHeaders.put("X-Trace-Id", "trace-002"); HttpResponse r2 = http.postJson(postUrl, postHeaders, json); System.out.println("POST(JSON) status=" + r2.statusCode() + ", tookMs=" + r2.tookMs()); System.out.println(r2.body()); // 3) POST Form Map form = new HashMap<>(); form.put("username", "vincent"); form.put("password", "123456"); HttpResponse r3 = http.postForm(postUrl, null, form); System.out.println("POST(Form) status=" + r3.statusCode() + ", tookMs=" + r3.tookMs()); System.out.println(r3.body()); } }