删除client文件,添加部分progrest的console输入内容
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user