193 lines
7.5 KiB
TypeScript
193 lines
7.5 KiB
TypeScript
/************************************************************************************
|
||
* 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;
|
||
}
|
||
}
|