Files
18xchat/assets/Scripts/chat18x/network/transport/HttpManager.ts
T
2025-08-25 11:31:15 +08:00

100 lines
3.0 KiB
TypeScript

/**
* Http管理器
*
*/
import { sys } from "cc";
import SubManager from 'db://assets/Scripts/Sub/SubManager';
// 请求类型
export type HttpMethod = "GET" | "POST" | "PUT";
// 请求参数结构
export interface HttpSendOptions {
headers?: Record<string, string>;
responseType?: XMLHttpRequestResponseType;
rawBody?: Document | XMLHttpRequestBodyInit | null;
}
// 响应结构
export interface HttpRawResponse {
ok: boolean; // 是否 2xx
status: number; // HTTP 状态码,网络错误/超时为 0
body?: any; // xhr.response 或 xhr.responseText
error?: "timeout" | "network" | "http";
}
export class HttpManager {
private static _I: HttpManager | null = null;
public static get I(): HttpManager {
if (!HttpManager._I) HttpManager._I = new HttpManager();
return HttpManager._I;
}
private constructor() {}
/** 发起请求,供 ApiClient 使用 */
public async request(
url: string,
data: any,
method: HttpMethod = "GET",
opt: HttpSendOptions = {}
): Promise<HttpRawResponse> {
const xhr = new XMLHttpRequest();
// 超时
xhr.timeout = 10000;
// 响应类型
if (opt.responseType) xhr.responseType = opt.responseType;
if (method === "GET") {
url = url + this.buildQuery(data);
xhr.open(method, url, true);
if (sys.isNative) {
xhr.setRequestHeader("Accept-Encoding", "gzip,deflate");
xhr.setRequestHeader("Content-type", "text/html;charset=utf-8");
}
} else {
xhr.open(method, url, true);
}
if (opt.headers) {
Object.keys(opt.headers).forEach(k => xhr.setRequestHeader(k, opt.headers![k]));
}
return new Promise<HttpRawResponse>((resolve) => {
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
const ok = xhr.status >= 200 && xhr.status < 300;
const body = xhr.response ?? xhr.responseText ?? null;
if (!ok) {
SubManager.ShowPrompt(`网络错误(${xhr.status}),请稍后再试`);
}
resolve({ ok, status: xhr.status, body, error: ok ? undefined : "http" });
}
};
xhr.onerror = () => {
SubManager.ShowPrompt("网络错误,请检查网络连接");
resolve({ ok: false, status: 0, error: "network" });
};
xhr.ontimeout = () => {
SubManager.ShowPrompt("请求超时,请检查网络连接");
resolve({ ok: false, status: 0, error: "timeout" });
};
if (method === "GET") {
xhr.send();
} else {
if (opt.rawBody !== undefined) xhr.send(opt.rawBody ?? null);
else xhr.send(JSON.stringify(data ?? {}));
}
});
}
/**
* 把对象转 ?a=1&b=2 的查询串
*/
private buildQuery(json: any) {
if (!json || typeof json !== "object") return "";
const pairs = Object.keys(json).map(
k => encodeURIComponent(k) + "=" + encodeURIComponent(json[k])
);
return pairs.length ? "?" + pairs.join("&") : "";
}
}