[CocosCreator]CocosCreator网络通信:https + websocket + protobuf

环境

cocos creator版本:3.8.0

开发语言:ts

操作系统:windows

http部分

直接使用 XMLHttpRequest 创建http请求

// _getHttpUrl 方法自己写字符串拼接

    public httpPostJsonRequest(uri: string, headData: any, data: any, cb: Function) {
        let xhr: XMLHttpRequest = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState == XMLHttpRequest.DONE) {
                if (xhr.status == 200) {// statusText:OK https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/status
                    let jsonStr: string = xhr.responseText;
                    console.log('tg post response:', jsonStr);
                    cb && cb(null, "", jsonStr);
                }
            }
        }
        xhr.ontimeout = function (event: ProgressEvent) {
            console.log(`http post [${uri}] timeout!`);
            cb && cb(event, "Timeout!", "{}");
        };
        xhr.onerror = (event: ProgressEvent) => {
            console.error('XMLHttpRequest error', event);
            cb && cb(event, "Request error!", "{}");
        }
        let url: string = this._getHttpUrl(uri);
        xhr.open('POST', url);
        xhr.setRequestHeader("Content-type", "application/json");
        if (headData) {
            for (let k in headData) {
                xhr.setRequestHeader(k, headData[k]);
            }
        }
        let json = JSON.stringify(data);
        console.log('send http post request:', json);
        xhr.send(json);
    }

    public httpGetRequest(uri: string, headData: any, cb: NetCbFunc) {
        let xhr: XMLHttpRequest = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState == XMLHttpRequest.DONE) {
                if (xhr.status == 200) {// statusText:OK https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/status
                    let jsonStr: string = xhr.responseText;
                    console.log('http get response:', jsonStr);
                    cb && cb(null, '', jsonStr);
                }
            }
        }
        xhr.ontimeout = function (event: ProgressEvent) {
            console.log('http get request timeout!');
            cb && cb(event, "Timeout!", "{}");
        };
        xhr.onerror = (event: ProgressEvent) => {
            console.error('XMLHttpRequest error');
            cb && cb(event, "Request error!", "{}");
        }
        if (headData) {
            for (let k in headData) {
                xhr.setRequestHeader(k, headData[k]);
            }
        }
        let url: string = this._getHttpUrl(uri);
        xhr.open('GET', url);
        console.log('send TG get request:', url);
        xhr.send();
    }
websocket部分

websocket认证:因为ts的websocket不能修改header,所以在创建websocket的url参数里添加params作为Authorization认证数据,例如 let ws = new WebSocket("localhost/ws?token=xxxx");

protobuf部分
安装环境:
  1. protobufjs ^7.3.2:安装命令 npm install --save protobufjs
  2. protobufjs-cli:用于导出proto文件为js/ts,安装命令 npm i -g protobufjs-cli

不安装 protobufjs-cli 也可以,protobufjs可以直接读取proto文件,为了ts编写方便,做了转换。

转换命令(放在package.json的scripts下就行):

  1.     "build-proto:pbjs": "pbjs --dependency protobufjs/minimal.js --target static-module --wrap commonjs --out [导出路径]/proto.js [proto文件路径]/*.proto",

  2. "build-proto:pbts": "pbts --main --out [导出路径]/proto.d.ts [上一步js导出路径]/*.js"

ts代码引用:import proto from '[js导出路径]/proto.js';

多个proto文件都会编入到一个js里。

websocket + protobuf
let ws: WebSocket = null;
function connectGameServer() {
    ws = new WebSocket("localhost/ws?token=xxxx");
    ws.binaryType = "arraybuffer";
    ws.onopen = (ev: Event) => {}
    ws.onmessage = (ev: MessageEvent) => {
        // 解析protobuf
        onMessage(ev);
    }
    ws.onerror = (ev: Event) => {}
    ws.onclose = (ev: CloseEvent) => {}
}

function sendWebsocketMessage(buffer: Uint8Array) {
    if (ws.readyState === WebSocket.OPEN) {
        ws.send(buffer);
    }
}
// 发送
function sendRequest(msgId, req) {
    // 根据msgId获取到proto对应的类 msgClass
    const err = msgClass.verify(req);
    if (err) {
        console.log('sendRequest error:', err);
        return;
    }
    let obj: ProtoMsgClass = msgClass.create(req);
    let writer: protobufjs.Writer = msgClass.encode(obj);
    // Uint8Array 和 DataView 需要修改工程目录下的tsconfig.json文件,compilerOptions部分,
    // "allowSyntheticDefaultImports": true,
    // "target": "ES2019",
    // "lib": [ "ES2020",  "dom" ]
    let messageBuffer: Uint8Array = writer.finish();
    // 发送的数据格式需要和服务端对齐,这里的是瞎写的,反正组装成 Uint8Array 数据格式就行
    let dv = new DataView(new ArrayBuffer(123));
    dv.setInt32(0, messageBuffer.length);
    dv.setBigUint64(4, BigInt(msgId));
    // 网上找到的这个代码,因为vscode的错误提示改成自己写的一个方法了。
    // const targetBuffer = Buffer.concat([new Uint8Array(dv.buffer), messageBuffer])
    const targetBuffer = BufferConcat(new Uint8Array(dv.buffer), messageBuffer);
    this.sendWebsocketMessage(targetBuffer);
}

    public static BufferConcat(buf1: Uint8Array, buf2: Uint8Array): Uint8Array {
        let buf: Uint8Array = null;
        if (buf1 && buf2) {
            let len1 = buf1.length;
            let len2 = buf2.length;
            buf = new Uint8Array(len1 + len2);
            buf.set(buf1);
            buf.set(buf2, len1);
        }
        return buf;
    }
// 接收
function onMessage(ev: MessageEvent) {
    const binary = new Uint8Array(ev.data);
    // 解析格式和服务端对齐就行,123、456、789都是瞎写的
    const buf = binary.slice(123, 456);
    let view = new DataView(buf.buffer, 0);
    const msgId = +view.getBigUint64(0, false).toString();
    // 根据msgId获取msgClass
    if (msgClass) {
        const bodyBuf = binary.slice(789);
        const msg = msgClass.decode(bodyBuf);
        console.log('onMessage', msg);
        // 调用对应回调处理消息
    } else {
        console.log('onMessage no map class', msgId);
    }
}
参考:
  1. websocket进行Authorization验证_websocket authorization-CSDN博客
  2. 前端在WebSocket中加入Token_websocket添加请求头token-CSDN博客
  3. javascript - WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 - Stack Overflow
  4. Essential guide to WebSocket authentication
  5. 8 best WebSocket libraries for Node
  6. 在Javascript中将Uint8Array转换为BigInt-腾讯云开发者社区-腾讯云
  7. websocket创建时附加额外信息 [如自定义headers信息(利用nginx)]_websocket自定义header-CSDN博客
  8. 前端如何在 WebSocket 的请求头中使用标准 HTTP 头携带 Authorization 信息,添加请求头_websocket添加请求头-CSDN博客
  9. JS/TS项目中使用websocket与protobuf_ts protobuf-CSDN博客
  10. TS项目中使用Protobuf的解决方案_protobuf ts-CSDN博客
  11. cocos creator使用protobuf详细方案 - Creator 3.x - Cocos中文社区
  12. cocos creator使用protobuf详细方案 - Creator 3.x - Cocos中文社区
  13. WebSocket 客户端 | Cocos Creator
  14. cocos-test-projects/assets/cases/network/NetworkCtrl.ts at 07f5671e18ef3ed4494d8cba6c2f9499766467a6 · cocos/cocos-test-projects · GitHub
  15. CocosCreator中加入webSocket的使用 - Creator 2.x - Cocos中文社区
  16. Cocos Creator3.8 项目实战(十)使用 protobuf详细教程_cocoscreator protobuf-CSDN博客
  17. 在cocos creator TS 中如何使用protobuf(自动化,评论中有)_cocoscreator ts 面试-CSDN博客
  18. cocos creator中webSocket的使用及封装_cocos onfire-CSDN博客
  19. [CocosCreator]封装WebSocket网络管理器(包含心跳)_cocoscreater socket.io 设置心跳和超时-CSDN博客
  20. https://zhuanlan.zhihu.com/p/653165384
  21. https://zhuanlan.zhihu.com/p/616718383
  22. javascript uint8数组和uint32之间的转换_arcgis unit8转化为unit32-CSDN博客
  23. node.js - How can I fix compile time errors even using compiler options as target es6 and es2017 in Angular 7? - Stack Overflow
  24. WebSocket 的请求头(header)中如何携带 authorization
  25. https://peterolson.github.io/BigInteger.js/BigInteger.min.js
  26. https://github.com/yume-chan/dataview-bigint-polyfill
  27. https://github.com/peterolson/BigInteger.js
  28. CocosCreator与大整数运算库_ts 游戏中大数值怎么计算-CSDN博客
  29. 【分享】自定义arraybuffer数据结构 - Creator 2.x - Cocos中文社区
  30. DataView - JavaScript | MDN
  31. ES6,Number类型和新增的BigInt数据类型,以及数值精度丢失的问题_es6除号-CSDN博客
  32. CocosCreator 源码./polyfill/array-buffer详解 - 简书
  33. [ts]typescript高阶之typeof使用_ts typeof-CSDN博客
  34. TypeScript 【type】关键字的进阶使用方式_typescript type使用-CSDN博客
  35. 记录JS XMLHttpRequest POST提交JSON数据的格式_xmlrequest post json-CSDN博客
  36. JS使用XMLHttpRequest对象POST收发JSON格式数据_js发送json-CSDN博客
  37. https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
  • 25
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GrimRaider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值