103 lines
3.1 KiB
TypeScript
103 lines
3.1 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.rawBody) {
|
||
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
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("&") : "";
|
||
|
|
}
|
||
|
|
}
|