package com.knowledge.base.infrastructure.util; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeUnit; /** * OkHttp封装的 HTTP 客户端工具类(支持 JSON POST、GET、Token注入、泛型反序列化、流式请求) */ @Slf4j @Component public class HttpHelper { private final OkHttpClient client; private final ObjectMapper objectMapper; public HttpHelper() { this.client = new OkHttpClient.Builder() .connectTimeout(60, TimeUnit.SECONDS) .readTimeout(300, TimeUnit.SECONDS) .build(); this.objectMapper = new ObjectMapper(); } /** * 发送 POST JSON 请求,自动反序列化为 Map */ public Map postJson(String url, Map body, String token) throws IOException { Request request = buildJsonRequest(url, body, token, "POST"); return executeJson(request); } /** * 发送 GET 请求,自动反序列化为 Map */ public Map get(String url, String token) throws IOException { Request request = buildJsonRequest(url, null, token, "GET"); return executeJson(request); } /** * 流式 POST 请求,返回 Response 实例,调用方负责关闭 response.body().close() */ public Response postStream(String url, Map body, String token) throws IOException { String json = objectMapper.writeValueAsString(body); RequestBody requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8")); Request request = new Request.Builder() .url(url) .addHeader("Authorization", token) .addHeader("Accept", "text/event-stream") .addHeader("Connection", "keep-alive") .post(requestBody) .build(); return client.newCall(request).execute(); } /** * 构建 JSON 类型的 Request 请求 */ private Request buildJsonRequest(String url, Map body, String token, String method) throws IOException { RequestBody requestBody = null; if (body != null) { String json = objectMapper.writeValueAsString(body); requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8")); } Request.Builder builder = new Request.Builder().url(url); if (token != null && !token.isBlank()) { builder.header("Authorization", "Bearer " + token); } switch (method.toUpperCase()) { case "POST": builder.post(requestBody != null ? requestBody : RequestBody.create(new byte[0])); break; case "GET": builder.get(); break; case "PUT": builder.put(requestBody); break; case "DELETE": if (requestBody != null) { builder.delete(requestBody); } else { builder.delete(); } break; default: throw new IllegalArgumentException("不支持的请求方法:" + method); } return builder.build(); } /** * 通用 HTTP 请求方法,支持任意 method、headers、请求体,自动反序列化返回 * * @param url 请求地址 * @param method 请求方法,如 GET、POST、PUT、DELETE * @param headers 请求头(可选,可为 null) * @param body 请求体对象(可选,可为 null) * @param responseType 返回类型(例如 Map.class) * @param 泛型类型 * @return 反序列化后的对象 * @throws IOException 请求失败或 JSON 解析异常 */ /** * 通用 HTTP 请求方法,支持任意 method、headers、请求体,支持泛型 TypeReference 返回(Jackson) */ public T exchange(String url, String method, Map headers, Object body, TypeReference typeRef) throws IOException { RequestBody requestBody = null; if (body != null) { String json = objectMapper.writeValueAsString(body); requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8")); } Request.Builder builder = new Request.Builder().url(url); if (headers != null) { for (Map.Entry entry : headers.entrySet()) { builder.addHeader(entry.getKey(), entry.getValue()); } } switch (method.toUpperCase()) { case "POST": builder.post(requestBody != null ? requestBody : RequestBody.create(new byte[0])); break; case "PUT": builder.put(requestBody != null ? requestBody : RequestBody.create(new byte[0])); break; case "DELETE": builder.delete(requestBody != null ? requestBody : null); break; case "GET": default: builder.get(); break; } Request request = builder.build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("请求失败: " + response.code() + " - " + response.message()); } String json = response.body().string(); return objectMapper.readValue(json, typeRef); } } /** * 执行请求并解析为 Map */ private Map executeJson(Request request) throws IOException { try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("请求失败: " + response.code() + " - " + response.message()); } String json = response.body().string(); return objectMapper.readValue(json, new TypeReference<>() {}); } } }