kaven-utils
Version:
Utils for Node.js.
141 lines (140 loc) • 5.17 kB
JavaScript
/********************************************************************
* @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;
}
}
}