@writ/utils
Version:
My tool kit
222 lines (211 loc) • 6.81 kB
JavaScript
const noop = require('./noop');
const addQuery = require('./request-query-add');
/**
* 获取对应的的请求对象
* XMLRequest对象在高版本标准浏览器里是不存在参数的,传入参数值不会影响其运行
**/
function getXhr(any) {
return new XMLRequest(any || XMLRequest.microsoft);
}
/**
* 获取返回数据
* @param {XMLHttpRequest} xhr
*/
function getBody(xhr) {
var text = xhr.responseText || xhr.response;
if (!text) {
return text;
}
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
// --------------------------------------------------------
// utlis end /
/**
* 全局缓存 XMLHttpRequest 对象
* @desc xhr.setRequestHeader('If-Modified-Since', '0'); 禁用缓存
* @desc get head post put delete connect options trace patch
* GET 方法请求一个指定资源的表示形式.使用GET的请求应该只被用于获取数据.
* HEAD 方法请求一个与GET请求的响应相同的响应, 但没有响应体.
* POST 方法用于将实体提交到指定的资源, 通常导致状态或服务器上的副作用的更改.
* PUT 方法用请求有效载荷替换目标资源的所有当前表示。
* DELETE 方法删除指定的资源。
* CONNECT 方法建立一个到由目标资源标识的服务器的隧道。
* OPTIONS 方法用于描述目标资源的通信选项。
* TRACE 方法沿着到目标资源的路径执行一个消息环回测试。
* PATCH 方法用于对资源应用部分修改
**/
var XMLRequest = null;
if (XMLHttpRequest) {
XMLRequest = XMLHttpRequest;
} else {
XMLRequest = ActiveXObject;
XMLRequest.microsoft = 'Microsoft.XMLHTTP';
}
var CONFIG = {
/** @param {string} method http连接的方式,包括POST和GET两种方式 */
method: 'GET',
/** @param {string} url 发送请求的url */
url: undefined,
/** @param {boolean} async 是否为异步请求,true为异步的,false为同步的 */
async: true,
/** @param {string} ie 传递给 ie 低版本的参数 */
ie: undefined,
/** @param {object} data 发送的参数,格式为对象类型 */
data: null,
/** @param {string} query 添加到URL上的参数 */
query: undefined,
/** @param {object} headers 发送的请求头,格式为对象类型 */
headers: null,
/** @param {boolean} cache 是否 URL 缓存请求 */
cache: false,
/** @param {boolean} withCredentials 是否发送cookie */
withCredentials: true,
/** @param {object} timeout 请求超时时间 */
timeout: 50000,
/** @param {function} onBefore 发送前执行的回调函数 */
onBefore: noop,
/** @param {function} onSuccess 发送并接收成功调用的回调函数 */
onSuccess: noop,
/** @param {function} onError 请求出错时执行的回调函数 */
onError: noop,
/** @param {function} onFinally 请求完成执行的回调函数 */
onFinally: noop,
/** @param {function} onTimeout 请求超时 */
onTimeout: noop,
/** @param {function} onProgress 上传进度处理 */
onProgress: noop,
/** @param {function} onload 上传结束 */
onload: noop,
};
/**
* 合并配置到基础选项上
* @param {object} key - user options
* @param {..any} value - user options' value
*/
function setConfig(key, value) {
if (arguments.length > 1) {
if (key in CONFIG) {
CONFIG[key] = value;
return;
}
}
if (typeof key !== 'object') {
throw new Error('key must be an object.');
}
for (var k in key) {
if (k in CONFIG) {
value = key[k];
if (typeof value === 'undefined') continue;
CONFIG[k] = value;
}
}
}
/**
* 合并请求参数
* @param {CONFIG} opt
*/
function getOption(opt) {
var option = Object.assign({}, CONFIG, opt);
if (!option.url) {
throw new Error('Invalid Request URL');
}
option.method = (opt.method || CONFIG.method).toUpperCase();
option.timeout = option.timeout > 0 ? option.timeout : CONFIG.timeout;
option.onBefore = typeof option.onBefore !== 'function' ? CONFIG.onBefore : option.onBefore;
option.onSuccess = typeof option.onSuccess !== 'function' ? CONFIG.onSuccess : option.onSuccess;
option.onError = typeof option.onError !== 'function' ? CONFIG.onError : option.onError;
option.onFinally = typeof option.onFinally !== 'function' ? CONFIG.onFinally : option.onFinally;
option.onProgress = typeof option.onProgress !== 'function' ? CONFIG.onProgress : option.onProgress;
option.onTimeout = typeof option.onTimeout !== 'function' ? CONFIG.onTimeout : option.onTimeout;
option.onload = typeof option.onload !== 'function' ? CONFIG.onload : option.onload;
return option;
}
/**
* 发送请求
* @param {CONFIG} opts
*/
function request(opts) {
var data;
var opt = getOption(opts);
var xhr = getXhr(opt.ie);
var headers = opt.headers || {};
opt.url += addQuery(opt.method, opt.query, opt.data, opt.cache);
if (opt.onBefore(xhr, opt) === false) {
return;
}
xhr.timeout = opt.timeout;
xhr.ontimeout = opt.onTimeout;
xhr.onload = opt.onload;
xhr.onerror = opt.onError;
if (xhr.upload) {
xhr.upload.onprogress = function progress(x, e) {
if (x.total > 0) {
x.percent = x.loaded / x.total * 100;
}
opt.onProgress(x, e);
};
} else {
xhr.onprogress = opt.onProgress;
}
xhr.onreadystatechange = function (xhr, e) {
if (xhr.readyState === 4) {
var body = getBody(xhr);
if (xhr.status < 200 || xhr.status >= 300) {
opt.onError(xhr, e, body);
} else {
opt.onSuccess(body, xhr);
}
}
opt.onFinally(xhr, e);
};
xhr.open(opt.method, opt.url, opt.async);
if (opt.withCredentials && 'withCredentials' in xhr) {
xhr.withCredentials = true;
}
// when set headers['X-Requested-With'] = null , can close default XHR header
// see https://github.com/react-component/upload/issues/33
if (headers['X-Requested-With'] !== null) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
// 禁用缓存
if (opt.cache === false && headers['If-Modified-Since'] == null) {
xhr.setRequestHeader('If-Modified-Since', '0');
}
for (var h in headers) {
if (headers.hasOwnProperty(h) && headers[h] !== null) {
xhr.setRequestHeader(h, headers[h]);
}
}
xhr.send(data || null);
return xhr;
}
module.exports = {
request,
setConfig,
http: {
post(url, data, success, error, progress) {
return request({
data,
method: 'post',
onError: error,
onSuccess: success,
onProgress: progress,
url,
});
},
get(url, data, success, error, progress) {
return request({
data,
method: 'get',
onError: error,
onSuccess: success,
onProgress: progress,
url,
});
}
},
};