Skip to content

Instantly share code, notes, and snippets.

@daixianceng
Last active July 6, 2020 11:26
Show Gist options
  • Select an option

  • Save daixianceng/a5968a55dabd4f04554dc3b27da9fcd3 to your computer and use it in GitHub Desktop.

Select an option

Save daixianceng/a5968a55dabd4f04554dc3b27da9fcd3 to your computer and use it in GitHub Desktop.
Pure javascript ajax request
var sha256 = require('sha256');
var baseUrl = 'http://127.0.0.1:8000';
var securityKey = '****';
var encryptSalt = '****';
/**
* 纯js实现的ajax
*
* ```js
* request.ajax(
* url: '', // 完整的url
* path: '', // 路径,将会与`baseUrl`拼装
* method: 'POST', // 方法,默认GET
* json: {}, // json数据
* form: new FormData(), // 使用`FormData`自定义数据
* sign: true, // 是否对json数据进行签名,默认true
* timeout: 30000, // 超时时间
* responseType: 'json', // 响应格式
* headers: {}, // 请求头
* success: data => {}, // 成功回调
* fail: data => {}, // 失败回调
* error: err => {}, // 错误回调,err有多种变体
* complete: res => {}, // 完成回调
* abort: err => {}, // 取消回调
* );
* ```
*
* Note: 该库默认请求与接收JSON数据,且加入了签名功能
*
* 关闭签名功能:request.ajax({ sign: false });
*/
module.exports = {
_headers: {
'Content-Type': 'application/json;charset=utf-8',
'Security-Key': securityKey,
},
addHeaders(headers) {
this._headers = Object.assign({}, this._headers, headers);
},
getHeaders() {
return this._headers;
},
removeHeader(key) {
delete this._headers[key];
},
/**
* 发起请求
*
* @param object options
* @return object XMLHttpRequest
*/
ajax(options) {
var oReq = new XMLHttpRequest();
oReq.responseType = options.responseType || 'json';
oReq.timeout = options.timeout || 30000;
oReq.open(options.method || 'GET', options.url || baseUrl + options.path);
var headers = options.headers
? Object.assign({}, this._headers, options.headers)
: this._headers;
this._setHeaders(oReq, headers);
var isSign = options.sign === false ? false : true;
var json = null;
if (options.json) {
if (isSign) {
json = {
...options.json,
sign: this.sign(options.json),
};
} else {
json = options.json;
}
}
oReq.onreadystatechange = function () {
try {
if (oReq.readyState === 4) {
if (oReq.response) {
if (oReq.response.status === 'success') {
if (options.success) {
options.success(oReq.response.data, oReq);
}
} else if (oReq.response.status === 'fail') {
if (options.fail) {
options.fail(oReq.response.data, oReq);
}
} else if (oReq.response.status === 'error') {
if (options.error) {
options.error(oReq.response.data, oReq);
}
}
}
if (options.complete) {
options.complete(oReq.response, oReq);
}
}
} catch (e) {
if (options.error) {
options.error(e, oReq);
}
}
};
oReq.addEventListener('abort', function (e) {
if (options.abort) {
options.abort(e, oReq);
}
});
oReq.addEventListener('error', function (e) {
if (options.error) {
options.error(e, oReq);
}
});
oReq.addEventListener('timeout', function (e) {
if (options.error) {
options.error(e, oReq);
}
});
if (json) {
oReq.send(JSON.stringify(json));
} else if (options.form) {
oReq.send(form);
} else {
oReq.send();
}
return oReq;
},
_retryCounts: {},
/**
* 可以发起重试的ajax
*
* 按理来说,应始终使用该方法来发起请求
*
* @param options options
*/
retryAjax(options, key) {
key = key || Math.random();
if (this._retryCounts[key] === undefined) this._retryCounts[key] = 0;
this._retryCounts[key]++;
this.ajax({
...options,
success: (...args) => {
delete this._retryCounts[key];
options.success && options.success(...args);
},
fail: (...args) => {
if (this._retryCounts[key] > 3) {
delete this._retryCounts[key];
options.fail && options.fail(...args);
// show toast
} else {
setTimeout(() => this.retryAjax(options, key), 3000);
}
},
error: (...args) => {
if (this._retryCounts[key] > 3) {
delete this._retryCounts[key];
options.error && options.error(...args);
// show toast
} else {
setTimeout(() => this.retryAjax(options, key), 3000);
}
},
});
},
_setHeaders(oReq, headers) {
for (var key in headers) {
oReq.setRequestHeader(key, headers[key]);
}
},
sign(args) {
var keys = Object.keys(args);
keys.sort();
var sa = [];
keys.forEach((k) => {
if (args[k]) {
sa.push(k + '=' + args[k]);
}
});
sa.push('salt:' + encryptSalt);
return sha256.hex(sa.join('&'), 'utf8').toUpperCase();
},
};
@daixianceng
Copy link
Author

daixianceng commented Jul 6, 2020

这是我在游戏中使用的代码,经过了生产测试,完美无瑕!其中默认使用了签名功能和JSON,可以在我的基础上更改或删掉

我的API结构只有这三种情况:

{
  status: 'success' | 'error' | 'fail',
  data: {
    message: 'required if error or fail',
    // other fields if request success
  }
}

所以,如果你的API不是很完美的话,可能也要更改代码

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment