/************************************************************************************ * 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; export type HeadersType = Record; export type BodiesType = Record; 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; } }