This commit is contained in:
parent
1d03e4283d
commit
cd27d50fb3
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
// //`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',
|
method: 'post',
|
||||||
//`timeout`选项定义了请求发出的延迟毫秒数
|
|
||||||
//如果请求花费的时间超过延迟的时间,那么请求会被终止
|
|
||||||
timeout: 60 * 1000,
|
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' },
|
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
|
||||||
// withCredentials: false,//跨域请求时是否携带cookie
|
responseType: 'json'
|
||||||
responseType: 'json',//响应数据类型
|
} as const;
|
||||||
// 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;
|
|
||||||
|
|
@ -1,10 +1,58 @@
|
||||||
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.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
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
|
||||||
|
// 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 => {
|
||||||
// (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) {
|
||||||
|
|
@ -17,26 +65,26 @@ service.interceptors.request.use(
|
||||||
// };
|
// };
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
( error: any) => {
|
(error: any) => 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 = 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 = {};
|
||||||
// if (data.code === 500) {
|
try {
|
||||||
// console.log(error)
|
data = JSON.parse(error.response.data);
|
||||||
// };
|
} catch (e) {
|
||||||
return data
|
data = error.response?.data || {};
|
||||||
}
|
}
|
||||||
)
|
return data;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default service;
|
return service;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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还没拿到合法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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue