mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-03 03:10:50 +08:00
88 lines
2.7 KiB
JavaScript
88 lines
2.7 KiB
JavaScript
// API 客户端:负责规范化基础地址、构造完整 URL、发送请求并回传版本信息
|
||
export class ApiClient {
|
||
constructor({ apiBase = '', managementKey = '', onVersionUpdate = null } = {}) {
|
||
this.apiBase = '';
|
||
this.apiUrl = '';
|
||
this.managementKey = managementKey || '';
|
||
this.onVersionUpdate = onVersionUpdate;
|
||
this.setApiBase(apiBase);
|
||
}
|
||
|
||
buildHeaders(options = {}) {
|
||
const customHeaders = options.headers || {};
|
||
const headers = {
|
||
'Authorization': `Bearer ${this.managementKey}`,
|
||
...customHeaders
|
||
};
|
||
const hasContentType = Object.keys(headers).some(key => key.toLowerCase() === 'content-type');
|
||
const body = options.body;
|
||
const isFormData = typeof FormData !== 'undefined' && body instanceof FormData;
|
||
if (!hasContentType && !isFormData) {
|
||
headers['Content-Type'] = 'application/json';
|
||
}
|
||
return headers;
|
||
}
|
||
|
||
normalizeBase(input) {
|
||
let base = (input || '').trim();
|
||
if (!base) return '';
|
||
base = base.replace(/\/?v0\/management\/?$/i, '');
|
||
base = base.replace(/\/+$/i, '');
|
||
if (!/^https?:\/\//i.test(base)) {
|
||
base = 'http://' + base;
|
||
}
|
||
return base;
|
||
}
|
||
|
||
computeApiUrl(base) {
|
||
const normalized = this.normalizeBase(base);
|
||
if (!normalized) return '';
|
||
return normalized.replace(/\/$/, '') + '/v0/management';
|
||
}
|
||
|
||
setApiBase(newBase) {
|
||
this.apiBase = this.normalizeBase(newBase);
|
||
this.apiUrl = this.computeApiUrl(this.apiBase);
|
||
return this.apiUrl;
|
||
}
|
||
|
||
setManagementKey(key) {
|
||
this.managementKey = key || '';
|
||
}
|
||
|
||
async request(endpoint, options = {}) {
|
||
const url = `${this.apiUrl}${endpoint}`;
|
||
const headers = this.buildHeaders(options);
|
||
|
||
const response = await fetch(url, {
|
||
...options,
|
||
headers
|
||
});
|
||
|
||
if (typeof this.onVersionUpdate === 'function') {
|
||
this.onVersionUpdate(response.headers);
|
||
}
|
||
|
||
if (!response.ok) {
|
||
const errorData = await response.json().catch(() => ({}));
|
||
throw new Error(errorData.error || `HTTP ${response.status}`);
|
||
}
|
||
|
||
return await response.json();
|
||
}
|
||
|
||
// 返回原始 Response,供下载/自定义解析使用
|
||
async requestRaw(endpoint, options = {}) {
|
||
const url = `${this.apiUrl}${endpoint}`;
|
||
const headers = this.buildHeaders(options);
|
||
const response = await fetch(url, {
|
||
...options,
|
||
headers
|
||
});
|
||
if (typeof this.onVersionUpdate === 'function') {
|
||
this.onVersionUpdate(response.headers);
|
||
}
|
||
return response;
|
||
}
|
||
}
|