78 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import http from "http";
 | |
| import https from "https";
 | |
| import { URL } from "url";
 | |
| import querystring from "querystring";
 | |
| import zlib from "zlib";
 | |
| const decompress = (data, encoding) => {
 | |
|     switch (encoding) {
 | |
|         case "br": return zlib.brotliDecompressSync(data);
 | |
|         case "gzip": return zlib.gunzipSync(data);
 | |
|         case "deflate": return zlib.inflateSync(data);
 | |
|     }
 | |
|     return data;
 | |
| };
 | |
| const readData = (res, mode) => new Promise((resolve, reject) => {
 | |
|     const chunks = [];
 | |
|     res
 | |
|         .on("data", chunk => chunks.push(chunk))
 | |
|         .on("end", () => {
 | |
|         try {
 | |
|             const data = decompress(Buffer.concat(chunks), res.headers["content-encoding"]);
 | |
|             if (mode === "json")
 | |
|                 resolve(JSON.parse(data.toString("utf8")));
 | |
|             else if (mode === "buffer")
 | |
|                 resolve(data);
 | |
|             else if (mode === "arraybuffer")
 | |
|                 resolve(new Uint8Array(data).buffer);
 | |
|             else
 | |
|                 resolve(data.toString("utf8"));
 | |
|         }
 | |
|         catch (err) {
 | |
|             reject(err);
 | |
|         }
 | |
|     })
 | |
|         .on("error", reject);
 | |
| });
 | |
| export default async (urlString, options = {}) => {
 | |
|     const { protocol, hostname, pathname, search, port } = new URL(urlString);
 | |
|     const body = options.method === "POST" && options.body
 | |
|         ? options.headers?.["Content-Type"] === "application/json"
 | |
|             ? JSON.stringify(options.body)
 | |
|             : querystring.stringify(options.body)
 | |
|         : null;
 | |
|     const requestOptions = {
 | |
|         hostname,
 | |
|         port: port || (protocol === "https:" ? 443 : 80),
 | |
|         path: pathname + search,
 | |
|         method: options.method || "GET",
 | |
|         headers: {
 | |
|             ...options.headers,
 | |
|             ...(body ? { "Content-Length": Buffer.byteLength(body) } : {}),
 | |
|             "Accept-Encoding": "br, gzip, deflate"
 | |
|         }
 | |
|     };
 | |
|     return new Promise((resolve, reject) => {
 | |
|         const requester = protocol === "https:" ? https : http;
 | |
|         const req = requester.request(requestOptions, res => {
 | |
|             if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300))
 | |
|                 return reject(new Error(`Request failed with status code ${res.statusCode}`));
 | |
|             resolve({
 | |
|                 body: res,
 | |
|                 headers: res.headers,
 | |
|                 text: () => readData(res, "text"),
 | |
|                 json: () => readData(res, "json"),
 | |
|                 buffer: () => readData(res, "buffer"),
 | |
|                 arrayBuffer: () => readData(res, "arraybuffer")
 | |
|             });
 | |
|         });
 | |
|         req.setTimeout(options.timeout || 5e3, () => {
 | |
|             req.destroy();
 | |
|             reject(new Error("Request timed out"));
 | |
|         });
 | |
|         req.on("error", reject);
 | |
|         if (body)
 | |
|             req.write(body);
 | |
|         req.end();
 | |
|     });
 | |
| };
 |