olympus-r
Version:
一个力求简单易用的前端开发框架 #### 开发语言 TypeScript #### 核心架构 MVC #### 模块间通讯和解耦 采用事件机制,利用一个全局唯一的事件派发器进行模块间通讯,解耦模块间依赖 #### 表现层结构 使用桥接模式拆分接口与实现,达到一套核心驱动多套表现层的目的(目前支持DOM、Egret、PixiJS三种表现层),同时支持表现层的未来可扩展性 #### TypeScript装饰器注入 框架提供TypeScript装饰器注入功能,便捷获取托管对象。例如:
220 lines (219 loc) • 7.75 kB
JavaScript
import * as tslib_1 from "tslib";
import { environment } from "../engine/env/Environment";
import { cloneObject } from "./ObjectUtil";
import { joinQueryParams, trimURL, validateProtocol } from "./URLUtil";
/**
* 发送一个或多个HTTP请求
*
* @export
* @param {IHTTPRequestParams} params 请求参数
*/
export function load(params) {
// 非空判断
if (!params.url) {
// 成功回调
params.onResponse && params.onResponse();
return;
}
// 数组判断
if (params.url instanceof Array) {
// 一次请求多个地址,需要做一个队列加载,然后一次性回调
var urls = params.url;
var results = [];
var newParams = cloneObject(params);
newParams.onResponse = function (result) {
results.push(result);
loadNext();
};
var loadNext = function () {
if (urls.length <= 0) {
// 成功回调
params.onResponse && params.onResponse(results);
return;
}
newParams.url = urls.shift();
load(newParams);
};
loadNext();
return;
}
// 一次请求一个地址
var retryTimes = params.retryTimes || 2;
var timeout = params.timeout || 10000;
var method = params.method || "GET";
var timeoutId = 0;
var data = params.data || {};
// 取到url
var url = params.url;
if (params.useCDN) {
// 如果使用CDN则改用cdn域名
url = environment.toCDNHostURL(url);
}
else {
// 合法化protocol
url = validateProtocol(url, params.forceHTTPS ? "https:" : null);
// 规整一下url
url = trimURL(url);
}
// 生成xhr
var xhr = (window["XDomainRequest"] && navigator.userAgent.indexOf("MSIE 10.") < 0 ? new window["XDomainRequest"]() : window["XMLHttpRequest"] ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
// 发送
send();
function send() {
var sendData = null;
// 根据发送方式组织数据格式
switch (method) {
case "POST":
switch (params.headerDict && params.headerDict["Content-Type"]) {
case "application/x-www-form-urlencoded":
// 使用webform格式(即query结构)字符串
sendData = toFormParams(data);
break;
case "multipart/form-data":
// 使用FormData对数据进行包装
sendData = new FormData();
for (var key_1 in data) {
sendData.append(key_1, data[key_1]);
}
break;
default:
// 其他都使用json包装为字符串
sendData = JSON.stringify(data);
break;
}
break;
case "GET":
// 将数据添加到url上
url = joinQueryParams(url, data);
break;
default:
throw new Error("暂不支持的HTTP Method:" + method);
}
// 打开XHR
xhr.open(method, url, true);
// 初始化,responseType必须在open之后设置,否则IE10和IE11会报错
if (params.responseType)
xhr.responseType = params.responseType;
// 如果需要withCredentials,则设置之
if (params.withCredentials)
xhr.withCredentials = true;
xhr.onload = onLoad;
xhr.onerror = onError;
// 添加自定义请求头,如果可以的话
if (xhr.setRequestHeader) {
for (var key in params.headerDict) {
xhr.setRequestHeader(key, params.headerDict[key]);
}
}
// 开始发送
xhr.send(sendData);
// 开始计时
timeoutId = window.setTimeout(onError, timeout);
}
function onLoad(evt) {
// 即使是onLoad也要判断下状态码,但如果没有状态码,比如说XDomainRequest就直接认为成功了
var statusHead = xhr.status ? Math.floor(xhr.status * 0.01) : 2;
switch (statusHead) {
case 2:
case 3:
// 2xx和3xx的状态码认为是成功
timeoutId && clearTimeout(timeoutId);
timeoutId = 0;
// 成功回调
params.onResponse && params.onResponse(xhr.response || xhr.responseText);
break;
case 4:
case 5:
// 4xx和5xx的状态码认为是错误,转调错误回调
onError();
break;
}
}
function onError() {
// 停止计时
timeoutId && clearTimeout(timeoutId);
timeoutId = 0;
// 失败重试,只有在状态码以5开头时才重试
if (Math.floor(xhr.status / 100) === 5 && retryTimes > 0) {
// 没有超过重试上限则重试
abortAndRetry();
}
else {
// 出错,如果使用CDN功能则尝试切换
if (params.useCDN && !environment.nextCDN()) {
// 还没切换完,重新加载
load(params);
}
else {
// 切换完了还失败,则汇报错误
params.onError && params.onError(new XHRError(xhr));
}
}
}
function abortAndRetry() {
// 重试次数递减
retryTimes--;
// 中止xhr
xhr.abort();
// 添加时间戳作为随机版本号
url = joinQueryParams(url, { _r: Date.now() });
// 重新发送
send();
}
}
/**
* 异步加载,用于异步编程,参数中的onResponse和onError将会失效
*
* @export
* @param {IHTTPRequestParams} params 请求参数
* @returns {(Promise<any|any[]>)}
*/
export function asyncLoad(params) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve, reject) {
params.onResponse = resolve;
params.onError = reject;
load(params);
})];
});
});
}
/**
* 将数据转换为form形式
*
* @export
* @param {*} data 要转换的数据
* @returns {string} 转换结果字符串
*/
export function toFormParams(data) {
var keys = Object.keys(data);
var params = keys.map(function (key) {
return encodeURIComponent(key) + "=" + encodeURIComponent(data[key]);
});
return params.join("&");
}
var XHRError = /** @class */ (function (_super) {
tslib_1.__extends(XHRError, _super);
function XHRError(xhr) {
var _this = _super.call(this, xhr.status ? xhr.status + " " + xhr.statusText : "请求错误,且无法获取错误信息") || this;
_this._xhr = xhr;
return _this;
}
Object.defineProperty(XHRError.prototype, "xhr", {
/**
* 获取错误对应的XMLHttpRequest对象
*
* @readonly
* @type {XMLHttpRequest}
* @memberof XHRError
*/
get: function () {
return this._xhr;
},
enumerable: true,
configurable: true
});
return XHRError;
}(Error));
export { XHRError };