123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- const sproto = require('sproto');
- const HttpUtil = require('./HttpUtil');
- cc.Class({
- name: 'HttpClient',
- properties: {
- _clientHost: undefined,
- _clientSender: undefined,
- _session: 0,
- _host: undefined,
- _port: undefined,
- _path: '',
- method: 'GET',
- secretCode: '',
- timeout: 10000
- },
- /**
- * 加载协议文件
- *
- * @author Wetion
- * @date 2019-03-22
- * @param {Array} protoPaths
- */
- loadProtoFiles (protoPaths) {
- if (HttpUtil.clientHost && HttpUtil.clientSender) {
- G.LogUtils.warn('Warn:HttpClient协议文件已经加载过');
- return;
- }
- if (!G.FuncUtils.isArray(protoPaths)) {
- G.LogUtils.warn('Warn:HttpClient加载协议文件参数不正确');
- return;
- }
- // 加载协议文件
- cc.loader.loadResArray(protoPaths, (err, assets) => {
- if (err) {
- G.LogUtils.error('Bug:HttpClient协议文件失败 ' + err);
- return;
- }
- let protos = {};
- assets.forEach(proto => {
- let schema = JSON.parse(proto.text);
- let data = sproto.createNew(new Uint8Array(schema));
- protos[proto._name] = data;
- });
- HttpUtil.init();
- HttpUtil.clientHost = protos.http_s2c.host();
- HttpUtil.clientSender = HttpUtil.clientHost.attach(protos.http_c2s);
- G.LogUtils.log('Info:HttpClient协议文件加载成功');
- cc.game.emit('e_nwk_http_sproto_done');
- // 释放资源
- for (const path of protoPaths) {
- cc.loader.releaseRes(path);
- }
- });
- },
- /**
- * 是否准备完成(发送消息的前提)
- *
- * @author Wetion
- * @date 2019-03-22
- * @returns {Boolean}
- */
- isReadyDone () {
- return HttpUtil.clientHost && HttpUtil.clientSender;
- },
- /**
- * 设置URL参数
- *
- * @author Wetion
- * @date 2019-03-28
- * @param {String} host
- * @param {Number} port
- * @param {String} path
- */
- setURLArgs (host, port, path) {
- this._host = host;
- this._port = port;
- this._path = path || '';
- },
- _isValidURLArgs () {
- return (G.FuncUtils.isIP(this._host) && G.FuncUtils.isPort(this._port) || G.FuncUtils.isDomain(this._host));
- },
- /**
- * 客户端请求服务器信息
- *
- * @author Wetion
- * @date 2019-03-22
- * @param {String} protoName
- * @param {Object} info
- * @param {Function} responseHandler
- */
- c2sRequest (protoName, info, responseHandler) {
- if (!this.isReadyDone()) {
- G.LogUtils.warn('Warn:HttpClient还未准备好');
- return;
- }
- if (!this._isValidURLArgs() || !protoName || !info) {
- G.LogUtils.error('Bug:HttpClient发送请求信息错误');
- return;
- }
- this._session++;
- let requestBuffer = G.FuncUtils.uint8ToBuffer(HttpUtil.clientSender(protoName, info, this._session));
- let sourceStr = G.FuncUtils.bufferToString(requestBuffer) + this.secretCode;
- let md5Str = MD5.hex(sourceStr);
- let url;
- if (G.FuncUtils.isIP(this._host)) {
- url = cc.js.formatStr('http://%s:%s/%s?sign=%s', this._host, this._port, this._path, md5Str);
- } else {
- url = cc.js.formatStr('https://%s/%s?sign=%s', this._host, this._path, md5Str);
- }
- let xhr = cc.loader.getXMLHttpRequest();
- xhr.onreadystatechange = () => {
- // 查看readyState其他值 https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState
- if (xhr.readyState === 4 && xhr.status == 200) {
- let responseInfo;
- try {
- // 解析数据
- let responseBuffer = HttpUtil.clientHost.dispatch(G.FuncUtils.bufferToUint8(xhr.response));
- // 避免native释放buffer导致 object already destroyed
- responseInfo = G.FuncUtils.clone(responseBuffer.result);
- G.LogUtils.log('\n<-- 网络返回 http session:', responseBuffer.session, 'proto name:', protoName, ' response info:', responseBuffer.result, '\n');
- } catch (error) {
- // 返回解析协议错误码
- responseInfo = {code: 0};
- // 解析数据异常
- let responseText = G.FuncUtils.bufferToString(xhr.response);
- try {
- // http的错误码是以JSON的形式存在
- let responseBuffer = JSON.parse(responseText);
- let errorCodeDesc = this._getXHRErrorCodeDesc(responseBuffer.code);
- G.LogUtils.error('\n<-- 网络返回 http session:', xhr.session, 'proto name:', protoName, ' http access error info:', errorCodeDesc + responseText, '\n');
- } catch (e) {
- // 如果解析JSON错误,那么这应该是数据有问题导致sproto解析不了
- G.LogUtils.error('\n<-- 网络返回 http session:', xhr.session, 'proto name:', protoName, ' sproto parse:', responseText, 'error\n');
- G.LogUtils.error(error);
- }
- }
- if (responseHandler) {
- responseHandler({requestInfo: xhr.requestInfo, responseInfo: responseInfo});
- } else {
- G.LogUtils.warn('Warn:HttpClient没有定义响应回调函数');
- }
- }
- };
- xhr.ontimeout = ()=> {
- G.LogUtils.warn('\n<-- 网络返回 http session:', xhr.session, 'proto name:', protoName, ' ontimeout');
- if (responseHandler) {
- responseHandler({requestInfo: xhr.requestInfo, responseInfo: {code: 400} });
- }
- };
- xhr.onerror = ()=> {
- G.LogUtils.warn('\n<-- 网络返回 http session:', xhr.session, 'proto name:', protoName, ' onerror');
- if (responseHandler) {
- responseHandler({requestInfo: xhr.requestInfo, responseInfo: {code: 400} });
- }
- };
- xhr.onabort = ()=> {
- G.LogUtils.warn('\n<-- 网络返回 http session:', xhr.session, 'proto name:', protoName, ' onabort');
- if (responseHandler) {
- responseHandler({requestInfo: xhr.requestInfo, responseInfo: {code: 400} });
- }
- };
- xhr.timeout = this.timeout;
- xhr.requestInfo = info;
- xhr.session = this._session;
- xhr.responseType = 'arraybuffer';
- xhr.open(this.method, url);
- G.LogUtils.log('--> 网络请求 http session:', this._session, 'proto name:', protoName, ' request info:', info, 'url:', url);
- xhr.send(requestBuffer); // Uint8Array is an ArrayBufferView
- },
- _getXHRErrorCodeDesc (code) {
- let desc = '';
- if (code == 500) {
- desc = '服务器数据校验失败';
- } else {
- desc = '没有错误码' + code + '的描述';
- }
- return desc;
- }
- });
|