liujie
2026-08-11 323764c813a09cd56cdab780155ef659dbe0b364
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/BaseDataApiUtil.java
@@ -1,6 +1,10 @@
package com.ruoyi.web.controller.tool;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
@@ -30,9 +34,11 @@
 */
public final class BaseDataApiUtil {
    public static final String DEFAULT_BASE_URL = "http://192.168.1.160:18888";
    public static final String DEFAULT_BASE_URL = "http://58.20.112.148:18888";
    private static final String BASE_URL_PROPERTY = "base.data.api.url";
    private static final String BASE_URL_ENV = "BASE_DATA_API_URL";
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_PREFIX = "Bearer ";
    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType OCTET_STREAM_MEDIA_TYPE = MediaType.parse("application/octet-stream");
    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
@@ -141,7 +147,7 @@
        requireContentType(api, RequestContentType.MULTIPART);
        String url = buildUrl(baseUrl, api.getPath(), pathVariables, null);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        addHeaders(requestBuilder, headers);
        addHeaders(requestBuilder, api, headers);
        applyMethod(requestBuilder, api.getMethod(), buildMultipartBody(fields, files));
        return executeString(requestBuilder.build());
    }
@@ -181,7 +187,7 @@
     */
    private static Request buildRequest(String baseUrl, Api api, Map<String, ?> pathVariables,
                                        Map<String, ?> params, Object explicitBody,
                                        Map<String, String> headers) {
                                        Map<String, String> headers) throws IOException {
        Objects.requireNonNull(api, "api");
        if (api.getRequestContentType() == RequestContentType.MULTIPART) {
            throw new IllegalArgumentException("multipart/form-data 接口请使用 requestMultipart 方法");
@@ -191,7 +197,7 @@
        String url = buildUrl(baseUrl, api.getPath(), pathVariables, queryParamRequest ? params : null);
        RequestBody body = queryParamRequest ? null : buildRequestBody(api, params, explicitBody);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        addHeaders(requestBuilder, headers);
        addHeaders(requestBuilder, api, headers);
        applyMethod(requestBuilder, api.getMethod(), body);
        return requestBuilder.build();
    }
@@ -377,18 +383,60 @@
    /**
     * 目的:追加自定义请求头,过滤空 header 名和空 header 值。
     */
    private static void addHeaders(Request.Builder builder, Map<String, String> headers) {
    private static void addHeaders(Request.Builder builder, Api api, Map<String, String> headers) throws IOException {
        addMiddlePlatformAuthorization(builder, api, headers);
        if (headers == null) {
            return;
        }
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            if (isNotBlank(entry.getKey()) && entry.getValue() != null) {
            if (isNotBlank(entry.getKey()) && isNotBlank(entry.getValue())) {
                builder.header(entry.getKey(), entry.getValue());
            }
        }
    }
    /**
     * 目的:除登录接口外,为所有中台请求统一添加当前登录态的 Bearer Token。
     */
    private static void addMiddlePlatformAuthorization(Request.Builder builder, Api api,
                                                        Map<String, String> headers) throws IOException {
        Objects.requireNonNull(api, "api");
        if (api == Api.POST_AUTH_USER_LOGIN || hasAuthorizationHeader(headers)) {
            return;
        }
        LoginUser loginUser;
        try {
            loginUser = SecurityUtils.getLoginUser();
        } catch (RuntimeException e) {
            throw new ServiceException("中台认证信息已失效,请重新登录", HttpStatus.UNAUTHORIZED);
        }
        String token = loginUser == null ? null : loginUser.getMiddlePlatformToken();
        if (!isNotBlank(token)) {
            if (loginUser != null && "local".equalsIgnoreCase(loginUser.getLoginSource())) {
                throw new ServiceException("当前账号未通过中台认证,无法查询中台数据", HttpStatus.FORBIDDEN);
            }
            throw new ServiceException("中台认证信息已失效,请重新登录", HttpStatus.UNAUTHORIZED);
        }
        builder.header(AUTHORIZATION_HEADER, BEARER_PREFIX + token.trim());
    }
    /**
     * 目的:允许调用方显式传入认证头,并由后续自定义请求头处理覆盖默认值。
     */
    private static boolean hasAuthorizationHeader(Map<String, String> headers) {
        if (headers == null) {
            return false;
        }
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            if (AUTHORIZATION_HEADER.equalsIgnoreCase(entry.getKey()) && isNotBlank(entry.getValue())) {
                return true;
            }
        }
        return false;
    }
    /**
     * 目的:执行请求并读取字符串响应,非 2xx 响应统一转为 IOException。
     */
    private static String executeString(Request request) throws IOException {