z-util-page
Version:
428 lines (427 loc) • 14.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Http = void 0;
const tslib_1 = require("tslib");
const index_1 = require("../deepClone/index");
const FileHelper = tslib_1.__importStar(require("../FileHelper/index"));
const message_1 = require("./message");
/**
* @category HTTTP请求操作辅助类
*/
class Http {
/**
* 构造函数
* @example
* ```ts
* const http = new Http({
* //超时等待时间(ms)
* timeout: 10000,
* //基地址
* baseUrl: 'http://localhost:3000',
* //请求体数据格式
* contentType: 'application/json',
* //响应数据格式
* responseType: 'json'
* });
* ```
* @param options 默认参数
*/
constructor(options = {}) {
/**
* 默认参数
*/
Object.defineProperty(this, "options", {
enumerable: true,
configurable: true,
writable: true,
value: {
timeout: 10000,
baseUrl: '',
contentType: '',
responseType: ''
}
});
/**
* 拦截器
*/
Object.defineProperty(this, "Interceptor", {
enumerable: true,
configurable: true,
writable: true,
value: {
requestArr: [],
responseArr: [],
request(func) {
if (typeof func === 'function')
this.requestArr.push(func);
},
response(func) {
if (typeof func === 'function')
this.responseArr.push(func);
}
}
});
Object.assign(this.options, options);
}
/**
* XMLHttpRequest异步请求
* @example
* ```ts
* const http = new Http();
* // 拦截器
* http.Interceptor.request((param) => {
* // 请求参数
* console.log(param);
* param.url = 'http://localhost:3000' + param.url;
* })
* http.Interceptor.response((res) => {
* // 请求结果
* console.log(res);
* res.data = res.data + '拦截器修改';
* return res;
* })
*
* // 请求
* const req = http.ajax({
* // 请求地址
* baseUrl: 'http://localhost:3000',
* url: '/api/user',
* // 请求方法
* method: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE',
* // 响应数据格式
* type: "arraybuffer" | "blob" | "document" | "json" | "text",
* // 请求头
* headers: {
* 'Content-Type': 'application/json',
* 'Authorization': 'Bearer ' + token
* }
* // 请求体
* data: {
* name: 'jack'
* }
* // 请求参数
* params: {
* name: 'jack'
* }
* // 请求超时时间
* timeout: 10000
* // 请求体数据格式
* contentType: 'application/json',
* // 响应数据类型
* responseType: 'json',
* // 上传文件
* file: {
* file: new Blob([JSON.stringify({a: '身体和心灵,总有一个在路上。'}, null, 2)], {type : 'application/json'})
* }
* }).then((res) => {
* // 请求成功
* }).catch((err) => {
* // 请求失败
* }).finally(() => {
* // 请求完成
* }).progress(() => {
* // 请求进度
* });
*
* // 取消请求
* req.abort();
* ```
* @param param 请求参数
*/
ajax(param) {
const xhr = new XMLHttpRequest();
submit.call(this, xhr, petchParam(param));
return new PromiseHandle(xhr).then(res => {
this.Interceptor.responseArr.forEach(func => {
res = func(res) || res;
});
return res;
});
}
/**
* XMLHttpRequest同步请求,绝大多数情况下只能在work进程内使用。
* @example
* ```ts
* const http = new Http();
* // 请求
* const req = http.ajax({
* // 请求地址
* baseUrl: 'http://localhost:3000',
* url: '/api/user',
* // 请求方法
* method: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE',
* // 响应数据格式
* type: "arraybuffer" | "blob" | "document" | "json" | "text",
* // 请求头
* headers: {
* 'Content-Type': 'application/json',
* 'Authorization': 'Bearer ' + token
* }
* // 请求体
* data: {
* name: 'jack'
* }
* // 请求参数
* params: {
* name: 'jack'
* }
* // 请求超时时间
* timeout: 10000
* // 请求体数据格式
* contentType: 'application/json',
* // 响应数据类型
* responseType: 'json',
* // 上传文件
* file: {
* file: new Blob([JSON.stringify({a: '身体和心灵,总有一个在路上。'}, null, 2)], {type : 'application/json'})
* }
* })
* // 请求成功
* console.log(res);
* ```
* @param param 请求参数
*/
ajaxAsync(param) {
const xhr = new XMLHttpRequest();
submit.call(this, xhr, petchParam(param), true);
let res = xhr.response;
this.Interceptor.responseArr.forEach(func => {
res = func(res) || res;
});
return res;
}
}
exports.Http = Http;
class PromiseHandle {
constructor(xhr) {
Object.defineProperty(this, "xhr", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "result", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.xhr = xhr;
this.xhr.addEventListener('load', () => {
this.result = this.xhr.response;
});
}
then(callback) {
this.xhr.addEventListener('load', () => {
callback(new message_1.Message(this.xhr));
});
return this;
}
catch(callback) {
this.xhr.addEventListener('error', () => {
callback(new message_1.Message(this.xhr));
});
return this;
}
finally(callback) {
this.xhr.addEventListener('loadend', () => {
callback(new message_1.Message(this.xhr));
});
return this;
}
progress(callback) {
this.xhr.addEventListener('progress', () => {
callback(new message_1.Message(this.xhr));
});
return this;
}
downProgress(callback) {
this.xhr.addEventListener('progress', (e) => {
if (e.lengthComputable) {
var percentComplete = e.loaded / e.total;
callback(new message_1.UploadMessage(this.xhr, '下载中', percentComplete.toFixed(4)));
}
else {
callback(new message_1.UploadMessage(this.xhr, '无法计算进度', null));
}
});
return this;
}
upProgress(callback) {
this.xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
var percentComplete = e.loaded / e.total;
callback(new message_1.UploadMessage(this.xhr, '上传中', percentComplete.toFixed(4)));
}
else {
callback(new message_1.UploadMessage(this.xhr, '无法计算进度', null));
}
});
return this;
}
abort() {
this.xhr.abort();
return this;
}
}
function warp(xhr, param, isInitHeader = true, isAsync = false, isGet = false) {
if (isInitHeader) {
const header = param.header || {};
Object.keys(header).forEach(key => {
if (isGet && key === 'ContentType')
return;
xhr.setRequestHeader(upperCase(key), header[key]);
});
if (!isGet && !header.ContentType)
xhr.setRequestHeader("Content-Type", this.options.contentType);
}
if (!isAsync) {
xhr.timeout = param.timeout || this.options.timeout;
xhr.responseType = param.responseType || this.options.responseType;
xhr.addEventListener('abort', function () {
console.warn('HTTP请求被中止');
});
xhr.addEventListener('error', function () {
console.warn(xhr.statusText);
});
xhr.addEventListener('timeout', function () {
console.warn('HTTP请求超时');
});
}
}
function submit(xhr, param, isAsync = false) {
this.Interceptor.requestArr.forEach(func => {
param = func(param) || param;
});
let baseUrl = this.options.baseUrl;
if (param.baseUrl !== undefined) {
baseUrl = String(param.baseUrl);
}
let url = baseUrl + (param.url || '');
let paramString = '';
if (param.param && Object.keys(param.param).length !== 0) {
let suffix = url.match(/(?:\?.*)$/);
paramString = suffix === null ? "?" : "&";
Object.keys(param.param || {}).forEach(key => {
paramString += (encodeURIComponent(key) + "=" + encodeURIComponent(param.param[key].toString()) + "&");
});
}
if (!param.method || (param.method && param.method.toUpperCase() === "GET")) {
xhr.open("GET", url + paramString, true);
warp.call(this, xhr, param, true, isAsync, true);
xhr.send(null);
}
else {
xhr.open(param.method, url + paramString, true);
let type = this.options.contentType;
if (param.header && param.header.ContentType)
type = param.header.ContentType;
const excute = Reflect.get(HttpHandle, type) || Reflect.get(HttpHandle, 'text/plain');
warp.call(this, xhr, param, type !== "multipart/form-data", isAsync, false);
excute.call(this, xhr, param);
}
}
function upperCase(val) {
if (val.length < 1)
return val;
let charts = val.split('');
charts[0] = charts[0].toLocaleUpperCase();
return charts.map((c, i) => {
if (c.match(/[A-Z]/) !== null && i !== 0)
return `-${c}`;
return c;
}).join('');
}
function petchParam(param) {
if (param.data === undefined)
param.data = {};
if (param.header === undefined)
param.header = {};
return param;
}
const HttpHandle = {
'application/x-www-form-urlencoded': function (xhr, param) {
let result = [];
Object.keys(param.data || {}).forEach(key => {
let val = param.data[key];
result.push(encodeURIComponent(key) + "=" + encodeURIComponent(val ? val.toString() : val));
});
Promise.resolve().then(() => {
xhr.send(result.join("&"));
});
},
'text/plain': function (xhr, param) {
let result = [];
Object.keys(param.data || {}).forEach(key => {
let val = param.data[key];
result.push(key.replace(/[\s\=\\]/g, "\\$&") + "=" + (val ? val.toString().replace(/[\s\=\\]/g, "\\$&") : val));
});
Promise.resolve().then(() => {
xhr.send(result.join("\r\n"));
});
},
'application/json': function (xhr, param) {
Promise.resolve().then(() => {
xhr.send(JSON.stringify(param.data || {}));
});
},
'multipart/form-data': function (xhr, param) {
const header = param.header || {};
Object.keys(header).forEach(key => {
if (key === "ContentType")
return;
xhr.setRequestHeader(upperCase(key), header[key]);
});
if (window.FormData) {
const formData = new FormData();
Object.keys(param.data || {}).forEach(key => {
formData.append(key, param.data[key]);
});
if (param.file)
Object.keys(param.file).forEach(key => {
formData.append(key, param.file[key]);
});
Promise.resolve().then(() => {
xhr.send(formData);
});
}
else {
let result = [];
Object.keys(param.data || {}).forEach(key => {
let val = param.data[key];
result.push("Content-Disposition: form-data; name=\"" + key + "\"\r\n\r\n" + (val ? val.toString() : val) + "\r\n");
});
let index = 0;
let boundary = "---------------------------" + Date.now().toString(16);
xhr.setRequestHeader("Content-Type", `multipart\/form-data; boundary=` + boundary);
if (param.file && (0, index_1.getType)(param.file) === "Object") {
Object.keys(param.file).forEach(key => {
let file = param.file[key];
let type = (0, index_1.getType)(file);
if (type === "File" || type === "Blob") {
index++;
FileHelper.read(file).load(function (res) {
let name = (window.File && file instanceof File) ? file.name : (key + '.blob');
result.push("Content-Disposition: form-data; name=\"" +
key + "\"; filename=\"" + name +
"\"\r\nContent-Type: " + (file.type ? file.type : "octet-stream") + "\r\n\r\n" + res.result + "\r\n");
}).loadend(function () {
index--;
if (index === 0) {
let combineResult = "--" + boundary + "\r\n" + result.join("--" + boundary + "\r\n") + "--" + boundary + "--\r\n";
Promise.resolve().then(() => {
xhr.send(combineResult);
});
}
}).start("BinaryString");
}
});
}
if (index === 0) {
Promise.resolve().then(() => {
xhr.send("--" + boundary + "\r\n" + result.join("--" + boundary + "\r\n") + "--" + boundary + "--\r\n");
});
}
}
}
};