|
@@ -1,42 +1,35 @@
|
|
|
|
|
|
|
|
-import { TikHubConfig } from './types.ts';
|
|
|
|
|
|
|
+import axios, { AxiosInstance } from 'axios';
|
|
|
|
|
+import { TikHubConfig, TikHubResponse } from './types.ts';
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* TikHub 客户端
|
|
* TikHub 客户端
|
|
|
* 直接调用 api.tikhub.io 的 API
|
|
* 直接调用 api.tikhub.io 的 API
|
|
|
- * 使用原生 fetch 替代 axios
|
|
|
|
|
*/
|
|
*/
|
|
|
export class TikHubClient {
|
|
export class TikHubClient {
|
|
|
- private readonly baseURL: string;
|
|
|
|
|
- private readonly apiKey: string;
|
|
|
|
|
- private readonly headers: Record<string, string>;
|
|
|
|
|
|
|
+ private axiosInstance: AxiosInstance;
|
|
|
|
|
+ private readonly BASE_URL = 'https://api.tikhub.io/api/v1';
|
|
|
|
|
+ private readonly API_KEY = 'tKIbAsEM8X+GmE2vHqGW7D/ICwK1Q5V4viKFrWiPB6HholGdLFqZJmmyNw==';
|
|
|
|
|
|
|
|
constructor(config?: Partial<TikHubConfig>) {
|
|
constructor(config?: Partial<TikHubConfig>) {
|
|
|
// 允许通过配置覆盖默认 Key 和 URL
|
|
// 允许通过配置覆盖默认 Key 和 URL
|
|
|
- this.apiKey = config?.apiKey || 'tKIbAsEM8X+GmE2vHqGW7D/ICwK1Q5V4viKFrWiPB6HholGdLFqZJmmyNw==';
|
|
|
|
|
- this.baseURL = config?.serverURL || 'https://api.tikhub.io/api/v1';
|
|
|
|
|
-
|
|
|
|
|
- this.headers = {
|
|
|
|
|
- 'Authorization': `Bearer ${this.apiKey}`,
|
|
|
|
|
- 'Content-Type': 'application/json'
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const apiKey = config?.apiKey || this.API_KEY;
|
|
|
|
|
+ const baseURL = config?.serverURL || this.BASE_URL;
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 构建完整 URL(包含查询参数)
|
|
|
|
|
- */
|
|
|
|
|
- private buildURL(path: string, params?: Record<string, any>): string {
|
|
|
|
|
- const url = new URL(path, this.baseURL);
|
|
|
|
|
-
|
|
|
|
|
- if (params) {
|
|
|
|
|
- Object.entries(params).forEach(([key, value]) => {
|
|
|
|
|
- if (value !== undefined && value !== null) {
|
|
|
|
|
- url.searchParams.append(key, String(value));
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return url.toString();
|
|
|
|
|
|
|
+ this.axiosInstance = axios.create({
|
|
|
|
|
+ baseURL,
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ // TikHub 要求使用 Authorization: Bearer <token>
|
|
|
|
|
+ 'Authorization': `Bearer ${apiKey}`,
|
|
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 添加请求拦截器用于调试
|
|
|
|
|
+ this.axiosInstance.interceptors.request.use(request => {
|
|
|
|
|
+ console.log(`[TikHub] ${request.method?.toUpperCase()} ${request.baseURL}${request.url}`, request.params || request.data);
|
|
|
|
|
+ return request;
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -44,36 +37,16 @@ export class TikHubClient {
|
|
|
* @param url 请求路径
|
|
* @param url 请求路径
|
|
|
* @param params 查询参数
|
|
* @param params 查询参数
|
|
|
*/
|
|
*/
|
|
|
- async get<T = any>(url: string, params: Record<string, any> = {}): Promise<T> {
|
|
|
|
|
- const fullURL = this.buildURL(url, params);
|
|
|
|
|
-
|
|
|
|
|
- console.log(`[TikHub] GET ${fullURL}`);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ async get<T = any>(url: string, params: any = {}): Promise<T> {
|
|
|
try {
|
|
try {
|
|
|
- const response = await fetch(fullURL, {
|
|
|
|
|
- method: 'GET',
|
|
|
|
|
- headers: this.headers
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (!response.ok) {
|
|
|
|
|
- const errorText = await response.text();
|
|
|
|
|
- let errorData;
|
|
|
|
|
- try {
|
|
|
|
|
- errorData = JSON.parse(errorText);
|
|
|
|
|
- } catch {
|
|
|
|
|
- errorData = { message: errorText };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- console.error(`TikHub API Error [GET ${url}]:`, errorData);
|
|
|
|
|
- console.error('Error Details:', JSON.stringify(errorData, null, 2));
|
|
|
|
|
-
|
|
|
|
|
- throw new Error(`HTTP ${response.status}: ${JSON.stringify(errorData)}`);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const data = await response.json();
|
|
|
|
|
- return data as T;
|
|
|
|
|
|
|
+ const response = await this.axiosInstance.get<T>(url, { params });
|
|
|
|
|
+ return response.data;
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
- console.error(`TikHub API Error [GET ${url}]:`, error.message);
|
|
|
|
|
|
|
+ console.error(`TikHub API Error [GET ${url}]:`, error.response?.data || error.message);
|
|
|
|
|
+ // 打印完整的错误响应,帮助排查 400 原因
|
|
|
|
|
+ if (error.response?.data) {
|
|
|
|
|
+ console.error('Error Details:', JSON.stringify(error.response.data, null, 2));
|
|
|
|
|
+ }
|
|
|
throw error;
|
|
throw error;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -83,35 +56,12 @@ export class TikHubClient {
|
|
|
* @param url 请求路径
|
|
* @param url 请求路径
|
|
|
* @param data 请求体
|
|
* @param data 请求体
|
|
|
*/
|
|
*/
|
|
|
- async post<T = any>(url: string, data: Record<string, any> = {}): Promise<T> {
|
|
|
|
|
- const fullURL = this.buildURL(url);
|
|
|
|
|
-
|
|
|
|
|
- console.log(`[TikHub] POST ${fullURL}`, data);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ async post<T = any>(url: string, data: any = {}): Promise<T> {
|
|
|
try {
|
|
try {
|
|
|
- const response = await fetch(fullURL, {
|
|
|
|
|
- method: 'POST',
|
|
|
|
|
- headers: this.headers,
|
|
|
|
|
- body: JSON.stringify(data)
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (!response.ok) {
|
|
|
|
|
- const errorText = await response.text();
|
|
|
|
|
- let errorData;
|
|
|
|
|
- try {
|
|
|
|
|
- errorData = JSON.parse(errorText);
|
|
|
|
|
- } catch {
|
|
|
|
|
- errorData = { message: errorText };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- console.error(`TikHub API Error [POST ${url}]:`, errorData);
|
|
|
|
|
- throw new Error(`HTTP ${response.status}: ${JSON.stringify(errorData)}`);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const responseData = await response.json();
|
|
|
|
|
- return responseData as T;
|
|
|
|
|
|
|
+ const response = await this.axiosInstance.post<T>(url, data);
|
|
|
|
|
+ return response.data;
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
- console.error(`TikHub API Error [POST ${url}]:`, error.message);
|
|
|
|
|
|
|
+ console.error(`TikHub API Error [POST ${url}]:`, error.response?.data || error.message);
|
|
|
throw error;
|
|
throw error;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|