2025-02-17 21:36:37 +08:00
|
|
|
|
/************************************************************************************
|
|
|
|
|
* FileName: HttpProto.ts
|
|
|
|
|
* Description:
|
|
|
|
|
*
|
|
|
|
|
* Version: v1.0.0
|
|
|
|
|
* Creator: Jacky(jackylvm@foxmail.com)
|
|
|
|
|
* CreationTime: 2024-04-22 15:09:20
|
|
|
|
|
* Copyright: 2021 - 2024
|
|
|
|
|
* ==============================================================
|
|
|
|
|
* History update record:
|
|
|
|
|
*
|
|
|
|
|
* ==============================================================
|
|
|
|
|
*************************************************************************************/
|
|
|
|
|
|
|
|
|
|
export type ParamsType = Record<string, string | number | boolean>;
|
|
|
|
|
export type HeadersType = Record<string, string | number | boolean>;
|
|
|
|
|
export type BodiesType = Record<string, any>;
|
|
|
|
|
export type RequestCallback = (err: Error | null, response: { type: XMLHttpRequestResponseType, data: any }) => void;
|
|
|
|
|
|
|
|
|
|
export enum HttpMethod {
|
|
|
|
|
GET = "GET",
|
|
|
|
|
POST = "POST",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class HttpProto {
|
|
|
|
|
private _requests: string[] = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GET请求
|
|
|
|
|
* @param {string} url 请求地址,不带参数
|
|
|
|
|
* @param {RequestCallback} callback 请求回调
|
|
|
|
|
* @param {ParamsType} params 请求查询参数,附加到url后面的查询参数
|
|
|
|
|
* @param {HeadersType} headers 请求头
|
|
|
|
|
*/
|
|
|
|
|
public get(url: string, callback: RequestCallback, params: ParamsType = null, headers: HeadersType = null): void {
|
|
|
|
|
this.request(url, HttpMethod.GET, params, headers, {}, callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* POST请求
|
|
|
|
|
* @param {string} url 请求地址,不带参数
|
|
|
|
|
* @param {RequestCallback} callback 请求回调
|
|
|
|
|
* @param {BodiesType} bodies 请求体,post请求用到
|
|
|
|
|
* @param {ParamsType} params 请求查询参数,附加到url后面的查询参数
|
|
|
|
|
* @param {HeadersType} headers 请求头
|
|
|
|
|
* @param urlEncode
|
|
|
|
|
*/
|
|
|
|
|
public post(url: string, callback: RequestCallback, bodies: BodiesType | { req: BodiesType } = null, params: ParamsType = null, headers: HeadersType = null, urlEncode: boolean = true): void {
|
|
|
|
|
this.request(url, HttpMethod.POST, params, headers, bodies, callback, urlEncode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private request(
|
|
|
|
|
url: string, method: HttpMethod, params: ParamsType, headers: HeadersType,
|
|
|
|
|
bodies: BodiesType | { req: BodiesType }, callback: RequestCallback, urlEncode: boolean = true
|
|
|
|
|
): void {
|
|
|
|
|
if (!url) {
|
|
|
|
|
console.error("url is null");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let urlParams: string = this.makeURLParams(url, params);
|
|
|
|
|
|
|
|
|
|
let bodiesStr: string;
|
|
|
|
|
let urlBodies: any;
|
|
|
|
|
if (urlEncode) {
|
|
|
|
|
urlBodies = this.makeURLBodies(headers, bodies);
|
|
|
|
|
bodiesStr = urlBodies;
|
|
|
|
|
} else {
|
|
|
|
|
urlBodies = bodies;
|
|
|
|
|
bodiesStr = JSON.stringify(urlBodies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let key: string = `${method} ${urlParams} ${bodiesStr}`;
|
|
|
|
|
|
|
|
|
|
if (this._requests.indexOf(key) > -1) {
|
|
|
|
|
console.warn(`${key} is in requests`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this._requests.push(key);
|
|
|
|
|
|
|
|
|
|
let xhr: XMLHttpRequest = new XMLHttpRequest();
|
|
|
|
|
xhr.timeout = 10000;
|
|
|
|
|
|
|
|
|
|
xhr.onreadystatechange = (): void => {
|
|
|
|
|
// readyState的状态值
|
|
|
|
|
// 0,表示 XMLHttpRequest 实例已经生成,但是实例的open()方法还没有被调用。
|
|
|
|
|
// 1,表示open()方法已经调用,但是实例的send()方法还没有调用,仍然可以使用实例的setRequestHeader()方法,设定 HTTP 请求的头信息。
|
|
|
|
|
// 2,表示实例的send()方法已经调用,并且服务器返回的头信息和状态码已经收到。
|
|
|
|
|
// 3,表示正在接收服务器传来的数据体(body 部分)。这时,如果实例的responseType属性等于text或者空字符串,responseText属性就会包含已经收到的部分信息。
|
|
|
|
|
// 4,表示服务器返回的数据已经完全接收,或者本次接收已经失败。
|
|
|
|
|
if (xhr.readyState === 1) {
|
|
|
|
|
// 必须open方法调用后才能设置请求头
|
|
|
|
|
if (headers) {
|
|
|
|
|
for (let key in headers) {
|
|
|
|
|
if (key.indexOf("Content-Type") > -1 || key.indexOf("content-type") > -1) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
xhr.setRequestHeader(key, headers[key].toString());
|
|
|
|
|
}
|
|
|
|
|
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
|
|
|
} else {
|
|
|
|
|
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (xhr.readyState === 4) {
|
|
|
|
|
this._requests.splice(this._requests.indexOf(key), 1);
|
|
|
|
|
|
|
|
|
|
console.log(`[HttpProto>onreadystatechange:96]>>${xhr.status} ${xhr.statusText} ${xhr.responseType}`, xhr.response);
|
|
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
|
if (xhr.status === 200) {
|
|
|
|
|
callback(null, {type: xhr.responseType, data: xhr.response});
|
|
|
|
|
} else {
|
|
|
|
|
callback(new Error(`${xhr.status} ${xhr.statusText}`), null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
xhr.ontimeout = (): void => {
|
|
|
|
|
this._requests.splice(this._requests.indexOf(key), 1);
|
|
|
|
|
if (callback) {
|
|
|
|
|
callback(new Error(`${xhr.status} ${xhr.statusText}`), null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xhr.onerror = (): void => {
|
|
|
|
|
this._requests.splice(this._requests.indexOf(key), 1);
|
|
|
|
|
if (callback) {
|
|
|
|
|
callback(new Error(`${xhr.status} ${xhr.statusText}`), null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xhr.onabort = (): void => {
|
|
|
|
|
this._requests.splice(this._requests.indexOf(key), 1);
|
|
|
|
|
if (callback) {
|
|
|
|
|
callback(new Error(`${xhr.status} ${xhr.statusText}`), null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (method === HttpMethod.GET) {
|
|
|
|
|
xhr.open(method, urlParams, true);
|
|
|
|
|
xhr.send();
|
|
|
|
|
} else {
|
|
|
|
|
xhr.open(method, urlParams, true);
|
|
|
|
|
console.log("xhr ============ ",xhr)
|
|
|
|
|
console.log(typeof urlBodies)
|
|
|
|
|
// xhr.send(urlBodies);
|
|
|
|
|
let b = JSON.parse(urlBodies)
|
|
|
|
|
console.log(typeof b)
|
|
|
|
|
xhr.send(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private makeURLParams(url: string, params: ParamsType): string {
|
|
|
|
|
if (params) {
|
|
|
|
|
let lst: string[] = [];
|
|
|
|
|
for (let key in params) {
|
|
|
|
|
lst.push(`${key}=${params[key]}`);
|
|
|
|
|
}
|
|
|
|
|
let paramsStr: string = lst.join("&");
|
|
|
|
|
if (url.indexOf("?") > -1) {
|
|
|
|
|
url += `&${paramsStr}`;
|
|
|
|
|
} else {
|
|
|
|
|
if (paramsStr.length > 0) {
|
|
|
|
|
if (!url.endsWith("/")) {
|
|
|
|
|
url += "/";
|
|
|
|
|
}
|
|
|
|
|
url += `?${paramsStr}`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private makeURLBodies(headers: HeadersType, bodies: BodiesType): string {
|
|
|
|
|
let contentType: string = "application/json";
|
|
|
|
|
if (headers) {
|
|
|
|
|
contentType = headers["Content-Type"] as string;
|
|
|
|
|
}
|
|
|
|
|
let body: string = "";
|
|
|
|
|
if (bodies) {
|
|
|
|
|
if (contentType === "application/json") {
|
|
|
|
|
body = JSON.stringify(bodies);
|
|
|
|
|
} else if (contentType === "application/x-www-form-urlencoded") {
|
|
|
|
|
let lst: string[] = [];
|
|
|
|
|
for (let key in bodies) {
|
|
|
|
|
lst.push(`${key}=${bodies[key]}`);
|
|
|
|
|
}
|
|
|
|
|
body = lst.join("&");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
}
|