UNPKG

kaven-utils

Version:

Utils for Node.js.

141 lines (140 loc) 5.17 kB
/******************************************************************** * @author: Kaven * @email: kaven@wuwenkai.com * @website: http://blog.kaven.xyz * @file: [Kaven-Utils] /src/KavenRequest.ts * @create: 2023-12-08 10:56:19.378 * @modify: 2025-05-21 16:59:03.845 * @version: 5.4.5 * @times: 16 * @lines: 168 * @copyright: Copyright © 2023-2025 Kaven. All Rights Reserved. * @description: [description] * @license: [license] ********************************************************************/ import pkgFollowRedirects from "follow-redirects"; import { ConvertTo, FindKeyValuePair, HttpStandardRequestHeader_ContentLength, HttpStandardRequestHeader_ContentType, IsHttpsUrl } from "kaven-basic"; import { KavenRequestResult } from "./KavenRequestResult.js"; import { InternalLogger } from "./KavenUtility.Internal.js"; /** * @since 5.4.0 * @version 2025-05-21 */ export class KavenRequest { options = {}; headers; Url; RequestData; ResponseEncoding = "utf8"; constructor(url) { this.Url = url; } get IsHttps() { return IsHttpsUrl(this.Url); } ContainsHeader(name) { if (this.headers && FindKeyValuePair(this.headers, name, true)) { return true; } return false; } UpdateHeader(name, value) { this.headers ??= {}; this.headers[name] = value; } UpdateHeaderIfNotExists(name, value) { if (this.ContainsHeader(name)) { return false; } this.UpdateHeader(name, value); return true; } async Execute(timeout) { const http = pkgFollowRedirects.http; const https = pkgFollowRedirects.https; const httpRequest = http.request; const httpsRequest = https.request; return new Promise((resolve, reject) => { const isHttps = this.IsHttps; let dataToWrite = ConvertTo(this.RequestData); if (dataToWrite) { if (!this.ContainsHeader(HttpStandardRequestHeader_ContentLength)) { let contentType = ""; // Determine the data type and set Content-Type and Content-Length accordingly if (Buffer.isBuffer(dataToWrite)) { contentType = "application/octet-stream"; } else if (typeof dataToWrite === "string") { contentType = "text/plain"; } else if (typeof dataToWrite === "object") { dataToWrite = JSON.stringify(dataToWrite); contentType = "application/json"; } else { // Handle other data types if needed } this.UpdateHeader(HttpStandardRequestHeader_ContentLength, Buffer.byteLength(dataToWrite)); if (contentType) { this.UpdateHeaderIfNotExists(HttpStandardRequestHeader_ContentType, contentType); } } if (!this.options.method) { this.options.method = "POST"; } } if (!this.options.agent) { // Add following agent to avoid "Error: socket hang up" this.options.agent = isHttps ? new https.Agent({ keepAlive: true }) : new http.Agent({ keepAlive: true }); } if (timeout) { this.options.timeout = timeout; } this.options.headers = this.headers; const request = isHttps ? httpsRequest : httpRequest; const req = request(this.Url, this.options, (res) => { const { statusCode, statusMessage, headers } = res; if (this.ResponseEncoding) { res.setEncoding(this.ResponseEncoding); } const chunkList = []; res.on("data", (chunk) => { chunkList.push(chunk); }); res.on("end", () => { const result = new KavenRequestResult(chunkList, statusCode, statusMessage, headers); resolve(result); }); }); req.on("timeout", () => { req.destroy(new Error(`Request timed out (${this.options.timeout})`)); }); req.on("error", (err) => { reject(err); }); // Write data to request body if (dataToWrite) { req.write(dataToWrite); } req.end(); }); } async TryExecuteToText() { try { const r = await this.Execute(); return r?.Text; } catch (ex) { InternalLogger()?.Error(ex); return undefined; } } async TryExecuteToJson() { try { const r = await this.Execute(); return r?.Json; } catch (ex) { InternalLogger()?.Error(ex); return undefined; } } }