Compare commits

...

1 Commits
v1.0.0 ... main

Author SHA1 Message Date
hailin cd27d50fb3 . 2025-06-14 13:08:44 +08:00
4 changed files with 207 additions and 70 deletions

View File

@ -73,7 +73,12 @@ export default async function RootLayout({
return ( return (
<html lang={locale} dir={dir(locale)} suppressHydrationWarning> <html lang={locale} dir={dir(locale)} suppressHydrationWarning>
<head />
<head>
{/* 在这里注入 env.js路径按你实际放置的 public 目录) */}
<script src="/env.js"></script>
</head>
<body <body
className={cn( className={cn(
inter.className, inter.className,

View File

@ -1,31 +1,45 @@
export default { // export default {
// baseURL: 'http://103.39.218.177:8082', // // baseURL: 'http://103.39.218.177:8082',
baseURL: `${process.env.NEXT_PUBLIC_CLIENT_BASE_URL}`, // baseURL: `${process.env.NEXT_PUBLIC_CLIENT_BASE_URL}`,
method: 'post', // method: 'post',
//`timeout`选项定义了请求发出的延迟毫秒数 // //`timeout`选项定义了请求发出的延迟毫秒数
//如果请求花费的时间超过延迟的时间,那么请求会被终止 // //如果请求花费的时间超过延迟的时间,那么请求会被终止
timeout: 60 * 1000, // timeout: 60 * 1000,
//发送请求前允许修改数据 // //发送请求前允许修改数据
// transformRequest: [function (data: any) { // // transformRequest: [function (data: any) {
// return data; // // return data;
// }], // // }],
// //数据发送到then/catch方法之前允许数据改动 // // //数据发送到then/catch方法之前允许数据改动
// transformResponse: [function (data: any) { // // transformResponse: [function (data: any) {
// return data; // // return data;
// }], // // }],
// headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, // // headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
headers: { 'Content-Type': 'application/json; charset=UTF-8' }, // headers: { 'Content-Type': 'application/json; charset=UTF-8' },
// withCredentials: false,//跨域请求时是否携带cookie // // withCredentials: false,//跨域请求时是否携带cookie
responseType: 'json',//响应数据类型 // responseType: 'json',//响应数据类型
// xsrfCookieName: 'XSRF-TOKEN', // // xsrfCookieName: 'XSRF-TOKEN',
// xsrfHeaderName: 'X-XSRF-TOKEN', // // xsrfHeaderName: 'X-XSRF-TOKEN',
// onUploadProgress: function (progressEvent: any) { },//上传进度事件 // // onUploadProgress: function (progressEvent: any) { },//上传进度事件
// onDownloadProgress: function (progressEvent: any) { },//下载进度事件 // // onDownloadProgress: function (progressEvent: any) { },//下载进度事件
//`validateStatus`定义了是否根据http相应状态码来resolve或者reject promise // //`validateStatus`定义了是否根据http相应状态码来resolve或者reject promise
//如果`validateStatus`返回true(或者设置为`null`或者`undefined`),那么promise的状态将会是resolved,否则其状态就是rejected // //如果`validateStatus`返回true(或者设置为`null`或者`undefined`),那么promise的状态将会是resolved,否则其状态就是rejected
// validateStatus: function (status: number) { // // validateStatus: function (status: number) {
// return status >= 200 && status < 300 // 默认的 // // return status >= 200 && status < 300 // 默认的
// }, // // },
//`maxRedirects`定义了在nodejs中重定向的最大数量 // //`maxRedirects`定义了在nodejs中重定向的最大数量
// maxRedirects: 5 // // maxRedirects: 5
} as any; // } 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;
}

View File

@ -1,42 +1,90 @@
import axiosConfig from "./axios_config"; // import axiosConfig from "./axios_config";
import axios from 'axios'; // import axios from 'axios';
const service = axios.create(axiosConfig); // const service = axios.create(axiosConfig);
// 请求拦截 // // 请求拦截
service.interceptors.request.use( // service.interceptors.request.use(
config => { // config => {
// (config.headers as any).Authorization = 'Bearer' + ' ' + store.getState().chatgpt.token; // // (config.headers as any).Authorization = 'Bearer' + ' ' + store.getState().chatgpt.token;
// if (config.data) { // // if (config.data) {
// config.data = JSON.stringify(config.data); // // config.data = JSON.stringify(config.data);
// }; // // };
// if (config.method?.toLocaleLowerCase() === 'get') { // // if (config.method?.toLocaleLowerCase() === 'get') {
// config.paramsSerializer = function (params) { // // config.paramsSerializer = function (params) {
// return qs.stringify(params, { arrayFormat: 'repeat' }) // // return qs.stringify(params, { arrayFormat: 'repeat' })
// } // // }
// }; // // };
return config; // return config;
}, // },
( error: any) => { // ( error: any) => {
return Promise.reject(error); // return Promise.reject(error);
} // }
); // );
// 响应拦截 // // 响应拦截
service.interceptors.response.use( // service.interceptors.response.use(
(res: any) => { // (res: any) => {
// let data = JSON.parse(res.data); // // let data = JSON.parse(res.data);
let data = res.data; // let data = res.data;
console.log(data) // console.log(data)
return data; // return data;
}, // },
( error: { response: { data: string; }; }) => { // ( error: { response: { data: string; }; }) => {
let data = JSON.parse(error.response.data); // let data = JSON.parse(error.response.data);
// if (data.code === 500) { // // if (data.code === 500) {
// console.log(error) // // console.log(error)
// }; // // };
return data // return data
} // }
) // )
export default service; // 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;
}

View File

@ -0,0 +1,70 @@
const LOCAL_KEY = "SUPABASE_URL";
const MAX_RETRIES = 5;
const RETRY_DELAY = 1000;
export async function getRuntimeEnv(key: string): Promise<string | undefined> {
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还没拿到合法IPlocalStorage兜底: ${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;
}