UNPKG

@lakutata/core

Version:

Lakutata Framework Core

241 lines (232 loc) 7.99 kB
import {Plugin} from '../base/Plugin' import { get as needleGet, post as needlePost, put as needlePut, patch as needlePatch, head as needleHead, delete as needleDelete, request as needleRequest, ReadableStream } from 'needle' import {URL} from 'url' import {NeedleOptions as HttpRequestOptions} from 'needle' import {HttpRequestException} from '../exceptions/HttpRequestException' import fs from 'fs' declare module '../Core' { interface Application { HttpRequest: HttpRequest } } export class HttpRequest extends Plugin { /** * Multipart上传 * @param {{method?: "post" | "put", url: string | URL, filename?: string, file: string, contentType?: string, field?: string, options?: HttpRequestOptions}} setting * @returns {Promise<T>} */ public async multipartUpload<T = any>(setting: { method?: 'post' | 'put', url: string | URL, filename?: string, file: string, contentType?: string, field?: string, options?: HttpRequestOptions }): Promise<T> { return new Promise((resolve, reject) => { const method: 'post' | 'put' = setting.method ? setting.method : 'put' const url: string = setting.url.toString() const filename: string | undefined = setting.filename const file: string = setting.file const contentType: string = setting.contentType ? setting.contentType : 'application/octet-stream' const field: string = setting.field ? setting.field : 'file' const uploadDataObject = { [field]: { filename: filename, content_type: contentType, file: file } } if (!fs.existsSync(file)) return reject(new HttpRequestException([`File [${file}] does not exist`, method.toUpperCase(), url])) const fileStat: fs.Stats = fs.statSync(file) if (!fileStat.isFile()) return reject(new HttpRequestException([`[${file}] is not file`, method.toUpperCase(), url])) needleRequest(method, url, uploadDataObject, Object.assign(setting.options ? setting.options : {}, {multipart: true}), (error, response) => { if (error) { reject(new HttpRequestException([error.message, method.toUpperCase(), url.toString()])) } else { resolve(response.body) } }) }) } /** * 文件下载 * @param setting * @param {(exception: (HttpRequestException | null), isDone: boolean, progress: number) => void} progressCallback * @returns {Promise<void>} */ public async download(setting: { method?: 'get' | 'post', url: string | URL, filename: string, params?: { [key: string]: any } | string | null, options?: HttpRequestOptions }, progressCallback?: (exception: HttpRequestException | null, isDone: boolean, progress: number) => void): Promise<void> { return new Promise((resolve, reject) => { const method: 'get' | 'post' = setting.method ? setting.method : 'get' const filename: string = setting.filename const url: string = setting.url.toString() const params: { [key: string]: any } | string | null = setting.params ? setting.params : null const options: HttpRequestOptions = Object.assign(setting.options ? setting.options : {}, {output: filename}) const stream: ReadableStream = needleRequest(method, url, params, options) let dataSize: number = 0 let receivedDataSize: number = 0 let progress: number = 0 const internalProgressCallback = (exception: HttpRequestException | null, isDone: boolean, progress: number) => { if (progressCallback) progressCallback(exception, isDone, progress) if (exception) { reject(exception) } if (isDone) { resolve() } } stream .on('header', (statusCode, headers) => { dataSize = headers['content-length'] ? parseInt(headers['content-length']) : 0 internalProgressCallback(null, false, progress) }) .on('readable', () => { let chunk: Buffer | string while (chunk = stream.read()) { receivedDataSize += chunk.length if (dataSize > 0) { progress = (receivedDataSize / dataSize) * 100 } else { progress = 0 } fs.appendFileSync(filename, chunk) internalProgressCallback(null, false, progress) } }) .on('done', (downloadError => { let downloadException: HttpRequestException | null = null if (downloadError) { downloadException = new HttpRequestException([downloadError.message, method.toUpperCase(), url.toString()]) } else if (dataSize === 0) { downloadException = new HttpRequestException(['Received 0 length data from server', method.toUpperCase(), url.toString()]) } internalProgressCallback(downloadException, true, progress) })) .once('error', error => { internalProgressCallback(new HttpRequestException([error.message, method.toUpperCase(), url.toString()]), false, progress) }) }) } /** * Get请求 * @param {string | URL} url * @param {HttpRequestOptions} options * @returns {Promise<T>} */ public async get<T = any>(url: string | URL, options?: HttpRequestOptions): Promise<T> { return new Promise((resolve, reject) => { needleGet(url.toString(), options, (error, response) => { if (error) { reject(new HttpRequestException([error.message, 'GET', url.toString()])) } else { resolve(response.body) } }) }) } /** * Post请求 * @param {string | URL} url * @param body * @param {HttpRequestOptions} options * @returns {Promise<T>} */ public async post<T = any>(url: string | URL, body: { [key: string]: any } | string | Buffer | null, options?: HttpRequestOptions): Promise<T> { return new Promise((resolve, reject) => { needlePost(url.toString(), body, options, (error, response) => { if (error) { reject(new HttpRequestException([error.message, 'POST', url.toString()])) } else { resolve(response.body) } }) }) } /** * Put请求 * @param {string | URL} url * @param body * @param {HttpRequestOptions} options * @returns {Promise<T>} */ public async put<T = any>(url: string | URL, body: { [key: string]: any } | string | Buffer | null, options?: HttpRequestOptions): Promise<T> { return new Promise((resolve, reject) => { needlePut(url.toString(), body, options, (error, response) => { if (error) { reject(new HttpRequestException([error.message, 'PUT', url.toString()])) } else { resolve(response.body) } }) }) } /** * Patch请求 * @param {string | URL} url * @param body * @param {HttpRequestOptions} options * @returns {Promise<T>} */ public async patch<T = any>(url: string | URL, body: { [key: string]: any } | string | Buffer | null, options?: HttpRequestOptions): Promise<T> { return new Promise((resolve, reject) => { needlePatch(url.toString(), body, options, (error, response) => { if (error) { reject(new HttpRequestException([error.message, 'PATCH', url.toString()])) } else { resolve(response.body) } }) }) } /** * Delete请求 * @param {string | URL} url * @param body * @param {HttpRequestOptions} options * @returns {Promise<T>} */ public async delete<T = any>(url: string | URL, body: { [key: string]: any } | string | Buffer | null, options?: HttpRequestOptions): Promise<T> { return new Promise((resolve, reject) => { needleDelete(url.toString(), body, options, (error, response) => { if (error) { reject(new HttpRequestException([error.message, 'DELETE', url.toString()])) } else { resolve(response.body) } }) }) } /** * Head请求 * @param {string | URL} url * @param {HttpRequestOptions} options * @returns {Promise<boolean>} */ public async head(url: string | URL, options?: HttpRequestOptions): Promise<boolean> { return new Promise((resolve) => { needleHead(url.toString(), options, (error) => { if (error) { resolve(false) } else { resolve(true) } }) }) } }