删除client文件,添加部分progrest的console输入内容

This commit is contained in:
2025-06-05 21:28:00 +08:00
parent 1835e40526
commit ce4e621741
6 changed files with 59 additions and 344 deletions
+3 -2
View File
@@ -14,10 +14,10 @@ export type ApiResponse<T> = {
export type QueryParams = Record<string, string | number | boolean | undefined>;
// 获取 API 基础 URL
const API_BASE_URL = 'http://172.16.0.58:8008';
// const API_BASE_URL = 'http://nas.7bm.co:3000';
// const API_BASE_URL = 'http://172.18.0.100:3000';
const API_BASE_URL = 'http://nas.7bm.co:3000';
// const API_BASE_URL = 'http://172.16.0.119:9000/admin';
// export const API_BASE_URL = 'http://nas.7bm.co:3000';
// 文档URL前缀
export const DOCUMENT_URL = 'http://nas.7bm.co:9000/docauditai/';
@@ -205,6 +205,7 @@ export async function apiRequest<T>(
url,
headers
};
console.log(`📦 axios-client.ts->请求配置: \n${JSON.stringify(config)}`);
// 删除body属性,避免axios警告
if ('body' in config) {
-312
View File
@@ -1,312 +0,0 @@
// app/api/client.ts
import { mockData, type MockApiResponse } from './mock';
/**
* API响应类型
*/
export type ApiResponse<T> = {
data?: T;
error?: string;
status: number;
headers?: Record<string, string>; // 添加对响应头的支持
};
export type QueryParams = Record<string, string | number | boolean | undefined>;
// 获取 API 基础 URL
// const API_BASE_URL = 'http://172.18.0.100:3000';
const API_BASE_URL = 'http://nas.7bm.co:3000';
// const API_BASE_URL = 'http://172.16.0.119:9000/admin';
// export const API_BASE_URL = 'http://nas.7bm.co:3000';
// 文档URL前缀
export const DOCUMENT_URL = 'http://nas.7bm.co:9000/docauditai/';
// 是否使用模拟数据(开发环境使用)
const USE_MOCK_DATA = false; // 设置为true使用模拟数据,避免API连接问题
/**
* 将编码后的URL解码为可读格式
* @param url 编码后的URL
* @returns 解码后的可读URL
*/
function decodeUrlForDisplay(url: string): string {
try {
// 首先解码整个URL
const decodedUrl = decodeURIComponent(url);
// 如果URL中包含@符号作为前缀,则移除它
if (decodedUrl.startsWith('@')) {
return decodedUrl.substring(1);
}
return decodedUrl;
} catch (error) {
// 如果解码失败,返回原始URL
console.error('URL解码失败:', error);
return url;
}
}
/**
* 构建完整的 API URL
*/
function buildUrl(endpoint: string, params?: QueryParams): string {
let fullUrl;
// 检查endpoint是否已经是完整URL
if (endpoint.startsWith('http')) {
fullUrl = endpoint;
} else {
// 确保API_BASE_URL格式正确
const baseUrl = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL;
const path = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
fullUrl = `${baseUrl}${path}`;
}
try {
// 创建URL对象
const url = new URL(fullUrl);
// 添加查询参数
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
url.searchParams.append(key, String(value));
}
});
}
return url.toString();
} catch (error) {
console.error('URL构建错误:', fullUrl, error);
throw new Error(`无法构建URL: ${fullUrl}, 错误: ${error}`);
}
}
// 超时控制
const fetchWithTimeout = async (url: string, options: RequestInit, timeout = 5000) => {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
// console.log(`📦 client.ts->请求URL: ${decodeUrlForDisplay(url)}`);
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(id);
return response;
} catch (error) {
clearTimeout(id);
console.error(`📦 client.ts->请求请求失败: ${error}`);
// 检查是否是网络连接问题
if (error instanceof TypeError && error.message.includes('fetch failed')) {
console.error('网络连接错误,请检查API_BASE_URL配置是否正确');
}
throw error;
}
};
/**
* 获取模拟响应数据
*/
function getMockResponse<T>(endpoint: string): ApiResponse<T> {
// console.log(`[开发模式] 使用模拟数据: ${endpoint}`);
// 移除开头的斜杠以便于匹配
const path = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
// 查找匹配的模拟数据
for (const mockPath in mockData) {
const normalizedMockPath = mockPath.startsWith('/') ? mockPath.substring(1) : mockPath;
if (path === normalizedMockPath || path.startsWith(normalizedMockPath + '/')) {
// 如果是详情查询 (如 /evaluation_points/1)
if (path.includes('/') && path !== normalizedMockPath) {
const id = parseInt(path.split('/')[1]);
const mockDataItem = mockData[mockPath as keyof typeof mockData] as MockApiResponse<unknown>;
if (Array.isArray(mockDataItem.data)) {
const item = mockDataItem.data.find((item: {id: number}) => item.id === id);
if (item) {
return {
data: {
code: 0,
msg: "成功",
data: item
} as unknown as T,
status: 200
};
}
}
return { error: '未找到数据', status: 404 };
}
// 返回列表数据
return {
data: mockData[mockPath as keyof typeof mockData] as unknown as T,
status: 200
};
}
}
return { error: '没有匹配的模拟数据', status: 404 };
}
/**
* 通用 API 请求函数
*/
export async function apiRequest<T>(
endpoint: string,
options: RequestInit = {},
params?: QueryParams
): Promise<ApiResponse<T>> {
// 如果使用模拟数据,直接返回模拟响应
if (USE_MOCK_DATA) {
return getMockResponse<T>(endpoint);
}
try {
// 构建 URL
const url = buildUrl(endpoint, params);
// 设置默认请求头
const headers = new Headers(options.headers || {});
if (!headers.has('Content-Type') && options.method !== 'GET') {
headers.set('Content-Type', 'application/json');
}
if (!headers.has('Accept')) {
headers.set('Accept', 'application/json');
}
// 针对 PostgREST 的额外处理
if (endpoint.includes('evaluation_point_groups') && (options.method === 'POST' || options.method === 'PATCH')) {
// console.log('使用 PostgREST 特定配置处理请求');
// 确保请求体是有效的 JSON 对象
if (options.body && typeof options.body === 'string') {
try {
JSON.parse(options.body); // 验证 JSON 是否有效
} catch (e) {
console.error('请求体不是有效的 JSON:', options.body);
throw new Error('请求体必须是有效的 JSON');
}
}
}
// console.log(`client.ts->发送 ${options.method || 'GET'} 请求到: ${decodeUrlForDisplay(url)}`);
if (options.body) {
// console.log(`client.ts->请求体: \n${options.body}`);
}
// 发送请求,10秒超时
const response = await fetchWithTimeout(url, {
...options,
headers
}, 10000);
// 解析响应
let data = null;
let responseText = '';
try {
const contentType = response.headers.get('content-type');
responseText = await response.text();
if (contentType && contentType.includes('application/json') && response.status !== 204 && responseText) {
try {
data = JSON.parse(responseText);
} catch (e) {
console.error('响应不是有效的 JSON:', responseText);
throw new Error('服务器返回无效的 JSON 响应');
}
}
} catch (e) {
console.error('解析响应失败:', e);
// console.log('原始响应:', responseText);
}
// 收集响应头信息
const responseHeaders: Record<string, string> = {};
response.headers.forEach((value, key) => {
responseHeaders[key] = value;
});
// 打印响应信息
// console.log(`响应状态: ${response.status} ${response.statusText}`);
// console.log(`响应头:`, responseHeaders);
// console.log(`响应体:`, data || responseText);
// 检查 PostgREST 特定错误
if (!response.ok) {
if (response.status === 400) {
console.error('PostgREST 错误 - 无效请求:', data || responseText);
return {
error: data?.message || data?.msg || '无效的请求格式,请检查数据格式是否正确',
status: response.status,
headers: responseHeaders
};
} else if (response.status === 401) {
console.error('PostgREST 错误 - 未授权:', data || responseText);
return {
error: data?.message || data?.msg || '未授权,请检查认证信息',
status: response.status,
headers: responseHeaders
};
} else if (response.status === 403) {
console.error('PostgREST 错误 - 禁止访问:', data || responseText);
return {
error: data?.message || data?.msg || '没有权限执行此操作',
status: response.status,
headers: responseHeaders
};
} else if (response.status === 404) {
console.error('PostgREST 错误 - 资源不存在:', data || responseText);
return {
error: data?.message || data?.msg || '请求的资源不存在',
status: response.status,
headers: responseHeaders
};
} else {
console.error(`HTTP请求失败: ${response.status} - ${url}`, data || responseText);
return {
error: data?.message || data?.msg || `请求失败: ${response.status}`,
status: response.status,
headers: responseHeaders
};
}
}
// 检查API返回的状态码
if (data && 'code' in data && data.code !== 0) {
console.error(`API请求失败: ${data.message || data.msg || '未知错误'} - ${url}`);
return {
error: data.message || data.msg || '请求失败',
status: response.status,
headers: responseHeaders
};
}
return {
data,
status: response.status,
headers: responseHeaders
};
} catch (error) {
console.error('API请求失败:', error);
// 如果超时或网络错误,使用模拟数据(仅开发环境)
if (process.env.NODE_ENV !== 'production') {
console.warn('自动使用模拟数据作为回退');
return getMockResponse<T>(endpoint);
}
return {
error: error instanceof Error ? error.message : '未知错误',
status: 500
};
}
}
+53 -27
View File
@@ -6,14 +6,22 @@ import { handleApiError } from './error-handler';
* PostgresREST 特定的查询参数接口
*/
export interface PostgrestParams {
// 查询参数
select?: string;
// 排序参数
order?: string;
// 分页参数
limit?: number;
offset?: number;
// 过滤参数
filter?: Record<string, unknown>;
schema?: string; // 指定 PostgreSQL schema
or?: Array<Record<string, unknown>> | string; // 支持OR条件查询
[key: string]: unknown; // 允许添加其他参数
// 指定 PostgreSQL schema
schema?: string;
// 支持OR条件查询
or?: Array<Record<string, unknown>> | string;
// 其他参数
[key: string]: unknown;
// 自定义头部参数
headers?: Record<string, string>;
}
@@ -45,8 +53,9 @@ function decodeUrlForDisplay(url: string): string {
* @param endpoint 端点
* @param params 参数
* @param method HTTP 方法
* @param data 请求体数据(用于POST/PATCH请求)
*/
function logPostgrestQuery(endpoint: string, params?: QueryParams, method: string = 'GET'): void {
function logPostgrestQuery(endpoint: string, params?: QueryParams, method: string = 'GET', data?: Record<string, unknown>): void {
if (process.env.NODE_ENV !== 'production') {
// const baseUrl = 'http://172.16.0.119:9000/admin';
// const baseUrl = 'http://172.18.0.100:3000';
@@ -55,22 +64,37 @@ function logPostgrestQuery(endpoint: string, params?: QueryParams, method: strin
// 确保 endpoint 格式正确
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
// console.log('\n📦 PostgREST 查询日志 ======================start=============');
// console.log(`📦 HTTP 方法: ${method}`);
// console.log(`📦 API 端点: ${decodeUrlForDisplay(`${baseUrl}/${normalizedEndpoint}`)}`);
let fullUrl = `${baseUrl}/${normalizedEndpoint}`;
// if (params && Object.keys(params).length > 0) {
// console.log('📦 查询参数:');
// 如果有查询参数,将其添加到URL中
if (params && Object.keys(params).length > 0) {
const queryString = Object.entries(params)
.filter(([, value]) => value !== undefined)
.map(([key, value]) => {
// 处理特殊的PostgREST操作符(如eq, gt, lt等)
if (typeof value === 'string' && value.includes('.')) {
return `${key}=${encodeURIComponent(value)}`;
}
return `${key}=${encodeURIComponent(String(value))}`;
})
.join('&');
// // 以可读格式单独打印每个参数
// Object.entries(params).forEach(([key, value]) => {
// if (value !== undefined) {
// console.log(` - ${key}: ${JSON.stringify(value)}`);
// }
// });
// }
if (queryString) {
fullUrl += `?${queryString}`;
}
}
// console.log('PostgREST 查询日志=============================end============\n');
console.log('\n📦 PostgREST 查询日志 ========================');
console.log(`📦 HTTP 方法: ${method}`);
console.log(`📦 完整 URL: ${decodeUrlForDisplay(fullUrl)}`);
// 打印请求体数据(仅适用于POST/PATCH/PUT请求)
if (['POST', 'PATCH', 'PUT'].includes(method) && data) {
console.log('📦 请求体数据:');
console.log(JSON.stringify(data, null, 2));
}
console.log('📦 PostgREST 查询日志 ========================\n');
}
}
@@ -297,12 +321,12 @@ export async function postgrestPost<T, D = Record<string, unknown>>(endpoint: st
// 确保端点没有前导斜杠
const apiEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
// 打印查询信息(POST请求只打印端点)
logPostgrestQuery(apiEndpoint, undefined, 'POST');
// 预处理数据,确保所有字段类型符合 PostgreSQL 要求
const processedData = preprocessData(data as Record<string, unknown>);
// 打印查询信息
logPostgrestQuery(apiEndpoint, undefined, 'POST', processedData);
// 确保数据是合法的JSON对象
const requestBody = JSON.stringify(processedData);
// console.log(`准备发送 PostgreSQL 插入请求到: ${apiEndpoint}`);
@@ -422,16 +446,18 @@ export async function postgrestPut<T, D extends object>(
const apiEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
// 构建完整的URL,包含过滤条件
let fullEndpoint = apiEndpoint;
const fullEndpoint = apiEndpoint;
const queryParams: QueryParams = {};
if (filters) {
const filterString = Object.entries(filters)
.map(([key, value]) => `${key}=eq.${value}`)
.join('&');
fullEndpoint = `${apiEndpoint}?${filterString}`;
// 将过滤条件转换为PostgREST格式的查询参数
Object.entries(filters).forEach(([key, value]) => {
queryParams[key] = `eq.${value}`;
});
}
// 打印查询信息PUT请求只打印端点)
logPostgrestQuery(fullEndpoint, undefined, 'PATCH');
// 打印查询信息
logPostgrestQuery(fullEndpoint, queryParams, 'PATCH', data as unknown as Record<string, unknown>);
const response = await apiRequest<T>(
fullEndpoint,