From cd27d50fb3722749e2dfdf56ca1797178cd2b721 Mon Sep 17 00:00:00 2001
From: hailin
Date: Sat, 14 Jun 2025 13:08:44 +0800
Subject: [PATCH] .
---
apps/blogai/app/[locale]/layout.tsx | 7 +-
apps/blogai/lib/http/axios_config.ts | 76 +++++++++-------
apps/blogai/lib/http/service.ts | 124 +++++++++++++++++++--------
apps/blogai/lib/ipconfig.ts | 70 +++++++++++++++
4 files changed, 207 insertions(+), 70 deletions(-)
create mode 100644 apps/blogai/lib/ipconfig.ts
diff --git a/apps/blogai/app/[locale]/layout.tsx b/apps/blogai/app/[locale]/layout.tsx
index 6222db3..3ae813c 100644
--- a/apps/blogai/app/[locale]/layout.tsx
+++ b/apps/blogai/app/[locale]/layout.tsx
@@ -73,7 +73,12 @@ export default async function RootLayout({
return (
-
+
+
+ {/* 在这里注入 env.js(路径按你实际放置的 public 目录) */}
+
+
+
= 200 && status < 300 // 默认的
- // },
- //`maxRedirects`定义了在nodejs中重定向的最大数量
- // maxRedirects: 5
-} as any;
\ No newline at end of file
+// export default {
+// // baseURL: 'http://103.39.218.177:8082',
+// baseURL: `${process.env.NEXT_PUBLIC_CLIENT_BASE_URL}`,
+// method: 'post',
+// //`timeout`选项定义了请求发出的延迟毫秒数
+// //如果请求花费的时间超过延迟的时间,那么请求会被终止
+// timeout: 60 * 1000,
+// //发送请求前允许修改数据
+// // transformRequest: [function (data: any) {
+// // return data;
+// // }],
+// // //数据发送到then/catch方法之前允许数据改动
+// // transformResponse: [function (data: any) {
+// // return data;
+// // }],
+// // headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+// headers: { 'Content-Type': 'application/json; charset=UTF-8' },
+// // withCredentials: false,//跨域请求时是否携带cookie
+// responseType: 'json',//响应数据类型
+// // xsrfCookieName: 'XSRF-TOKEN',
+// // xsrfHeaderName: 'X-XSRF-TOKEN',
+// // onUploadProgress: function (progressEvent: any) { },//上传进度事件
+// // onDownloadProgress: function (progressEvent: any) { },//下载进度事件
+// //`validateStatus`定义了是否根据http相应状态码,来resolve或者reject promise
+// //如果`validateStatus`返回true(或者设置为`null`或者`undefined`),那么promise的状态将会是resolved,否则其状态就是rejected
+// // validateStatus: function (status: number) {
+// // return status >= 200 && status < 300 // 默认的
+// // },
+// //`maxRedirects`定义了在nodejs中重定向的最大数量
+// // maxRedirects: 5
+// } as any;
+
+
+import { getRuntimeEnv } from "./ipconfig";
+export async function getAxiosConfig() {
+ const ip = await getRuntimeEnv("SUPABASE_URL"); // 直接用你 lib/ipconfig 里的方法
+ if (!ip) throw new Error("SUPABASE_URL 获取失败,无法构建 axios 配置");
+ return {
+ baseURL: `http://${ip}:80`, // 端口如需动态可再加参数
+ method: 'post',
+ timeout: 60 * 1000,
+ headers: { 'Content-Type': 'application/json; charset=UTF-8' },
+ responseType: 'json'
+ } as const;
+}
\ No newline at end of file
diff --git a/apps/blogai/lib/http/service.ts b/apps/blogai/lib/http/service.ts
index 7f213a2..46dff15 100644
--- a/apps/blogai/lib/http/service.ts
+++ b/apps/blogai/lib/http/service.ts
@@ -1,42 +1,90 @@
-import axiosConfig from "./axios_config";
-import axios from 'axios';
+// import axiosConfig from "./axios_config";
+// import axios from 'axios';
-const service = axios.create(axiosConfig);
+// const service = axios.create(axiosConfig);
-// 请求拦截
-service.interceptors.request.use(
- config => {
- // (config.headers as any).Authorization = 'Bearer' + ' ' + store.getState().chatgpt.token;
- // if (config.data) {
- // config.data = JSON.stringify(config.data);
- // };
- // if (config.method?.toLocaleLowerCase() === 'get') {
- // config.paramsSerializer = function (params) {
- // return qs.stringify(params, { arrayFormat: 'repeat' })
- // }
- // };
- return config;
- },
- ( error: any) => {
- return Promise.reject(error);
- }
-);
+// // 请求拦截
+// service.interceptors.request.use(
+// config => {
+// // (config.headers as any).Authorization = 'Bearer' + ' ' + store.getState().chatgpt.token;
+// // if (config.data) {
+// // config.data = JSON.stringify(config.data);
+// // };
+// // if (config.method?.toLocaleLowerCase() === 'get') {
+// // config.paramsSerializer = function (params) {
+// // return qs.stringify(params, { arrayFormat: 'repeat' })
+// // }
+// // };
+// return config;
+// },
+// ( error: any) => {
+// return Promise.reject(error);
+// }
+// );
-// 响应拦截
-service.interceptors.response.use(
- (res: any) => {
- // let data = JSON.parse(res.data);
- let data = res.data;
- console.log(data)
- return data;
- },
- ( error: { response: { data: string; }; }) => {
- let data = JSON.parse(error.response.data);
- // if (data.code === 500) {
- // console.log(error)
- // };
- return data
- }
-)
+// // 响应拦截
+// service.interceptors.response.use(
+// (res: any) => {
+// // let data = JSON.parse(res.data);
+// let data = res.data;
+// console.log(data)
+// return data;
+// },
+// ( error: { response: { data: string; }; }) => {
+// let data = JSON.parse(error.response.data);
+// // if (data.code === 500) {
+// // console.log(error)
+// // };
+// return data
+// }
+// )
-export default service;
\ No newline at end of file
+// export default service;
+
+
+
+import { getAxiosConfig } from "./axios_config";
+import axios from "axios";
+
+// 动态生成 axios 实例,每次都能拿到最新 IP
+export async function getService() {
+ const axiosConfig = await getAxiosConfig();
+ const service = axios.create(axiosConfig);
+
+ // 请求拦截
+ service.interceptors.request.use(
+ config => {
+ // (config.headers as any).Authorization = 'Bearer' + ' ' + store.getState().chatgpt.token;
+ // if (config.data) {
+ // config.data = JSON.stringify(config.data);
+ // };
+ // if (config.method?.toLocaleLowerCase() === 'get') {
+ // config.paramsSerializer = function (params) {
+ // return qs.stringify(params, { arrayFormat: 'repeat' })
+ // }
+ // };
+ return config;
+ },
+ (error: any) => Promise.reject(error)
+ );
+
+ // 响应拦截
+ service.interceptors.response.use(
+ (res: any) => {
+ let data = res.data;
+ console.log(data);
+ return data;
+ },
+ (error: { response: { data: string } }) => {
+ let data = {};
+ try {
+ data = JSON.parse(error.response.data);
+ } catch (e) {
+ data = error.response?.data || {};
+ }
+ return data;
+ }
+ );
+
+ return service;
+}
diff --git a/apps/blogai/lib/ipconfig.ts b/apps/blogai/lib/ipconfig.ts
new file mode 100644
index 0000000..8d9867d
--- /dev/null
+++ b/apps/blogai/lib/ipconfig.ts
@@ -0,0 +1,70 @@
+const LOCAL_KEY = "SUPABASE_URL";
+const MAX_RETRIES = 5;
+const RETRY_DELAY = 1000;
+
+export async function getRuntimeEnv(key: string): Promise {
+ if (typeof window !== "undefined") {
+ let retries = 0;
+ while (retries < MAX_RETRIES) {
+ // 1. 尝试 window.RUNTIME_ENV 提取IP
+ const val = window.RUNTIME_ENV?.[key];
+ const ip = extractIp(val);
+ if (ip) {
+ if (key === "SUPABASE_URL") {
+ window.localStorage.setItem(LOCAL_KEY, val!); // 这里存原始值
+ console.log(`[env] [${key}] 命中 window.RUNTIME_ENV: ${val},提取IP: ${ip},已同步到localStorage`);
+ } else {
+ console.log(`[env] [${key}] 命中 window.RUNTIME_ENV: ${val},提取IP: ${ip}`);
+ }
+ return ip;
+ } else if (val) {
+ console.warn(`[env] [${key}] window.RUNTIME_ENV 有值但无法提取合法IP: ${val}`);
+ }
+
+ retries++;
+ // 2. 第3次开始查localStorage兜底
+ if (retries >= 2) {
+ const cached = window.localStorage.getItem(LOCAL_KEY);
+ const cachedIp = extractIp(cached);
+ if (cachedIp && key === "SUPABASE_URL") {
+ console.warn(`[env] [${key}] 第${retries}次重试后window.RUNTIME_ENV还没拿到合法IP,localStorage兜底: ${cached},提取IP: ${cachedIp}`);
+ return cachedIp;
+ }
+ }
+
+ if (retries < MAX_RETRIES) {
+ console.log(`[env] [${key}] window.RUNTIME_ENV 暂无合法IP,第${retries}次重试,${RETRY_DELAY}ms后再试...`);
+ await new Promise(res => setTimeout(res, RETRY_DELAY));
+ }
+ }
+
+ // 3. 所有重试和localStorage都失败
+ console.error(`[env] [${key}] window.RUNTIME_ENV、localStorage都无合法IP,返回undefined`);
+ return undefined;
+ } else {
+ // 服务端
+ const val = process.env[key];
+ const ip = extractIp(val);
+ console.log(`[env][server] 直接读取 process.env[${key}]:`, val, "提取IP:", ip);
+ return ip;
+ }
+}
+
+// --------- 需要配合的工具函数 ---------
+function isValidIp(ip: string | undefined): boolean {
+ if (!ip) return false;
+ const reg = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/;
+ return reg.test(ip);
+}
+
+function extractIp(str: string | undefined): string | undefined {
+ if (!str) return undefined;
+ if (isValidIp(str)) return str;
+ try {
+ const url = new URL(str);
+ if (isValidIp(url.hostname)) return url.hostname;
+ } catch {}
+ const match = str.match(/(\d{1,3}(?:\.\d{1,3}){3})/);
+ if (match && isValidIp(match[1])) return match[1];
+ return undefined;
+}