发现一个webman的websocket的时候,传输gzip数据,解析数据会出现 gzdecode data error

zh7314
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<script src="./../dist/pako.js"></script>
<script>

const obj = [
  { foo: 'bar', baz: 'baz' },
  { abra: 1, cadabra: 22222222222222222 }
]

let result = pako.gzip(encodeURIComponent(JSON.stringify(obj)), { to: "string" });

function send(result) {
  var xhr = new XMLHttpRequest;

  xhr.open('POST', 'http://www.yd.com/open/test', true);
  xhr.send(result);
}
send(result);

</script>
</html>
<body>
Sending objects to server, run server code to see result.
</body>

php接收端
laravel8框架 php8

            $in = file_get_contents("php://input");
            p($in);
            $res = json_decode(urldecode(gzdecode($in)), true);
            p($res);

可以正常接受解压数据
截图

但是在webman socket数据就会出问题
gzdecode 出现data error

/*
     * {
    createTime: 命令发送时间
    data:{} 修改的命令
    id: "7a"   websocket的id
    returnMessage: "success"
    status: "0"  0告诉前端需要根据data的命令修改  1无意义
    type: 0:连接成功,1:发送给当前连接的用户,2:发送信息给其他用户,3:发送选区位置信息,999:用户连接断开
    username: 用户名
    }
     * ‹mŽA EOÃ^¨…¸´r.*’â¥ôúœ‰qÁ„¼?ïg„„R ŸèÎ8c._uÁ*”•efý ÞââfvÍñ@+[¸&Ϭ#”àA@*^ò.Ü<›òD¬t²ûWØßֆþT· ÷?a«×kDZô–’ –5Þk(KŽOŒâ8ô¾hC·R bl±ŒÝ„ uÛW
     */
    public function onMessage(TcpConnection $connection, $data)
    {
        $key = $this->getUid($connection->getLocalIp(), $connection->getLocalPort(), $connection->worker->workerId, $connection->worker->id, $connection->id);

        $return = [];
        $return['createTime'] = time();
        $return['data'] = null;
        $return['returnMessage'] = 'success';
        $return['status'] = '1';
        $return['type'] = 0;
        $return['id'] = $key;
        $return['username'] = $key;

        if ($data == 'rub') {
            //心跳不回复
        } else {
            $in = json_decode(urldecode(gzdecode($data)), true);

//            $this->broadcast($key, $data);
//            $connection->send(json_encode($return));
//            $connection->send($data);
        }
    }

数据格式是 pako加密的

let result = pako.gzip(encodeURIComponent(JSON.stringify(obj)), { to: "string" });

接受到的数据格式
截图

目前怀疑是 回调的onMessage $data数据返回有问题导致无法正解析

2022年9月21日09:52:36

终于解决了webman对接问题
因为现在php8 default_charset = "UTF-8" PHP的默认处理字符集是utf-8
但是gzip的默认字符集是 ISO-8859-1, gzdecode函数处理也需要 ISO-8859-1字符集
参考了java版本的代码发现他也是转还了字符集
public static String uncompress(String str) throws IOException {
        if (str == null || str.length() == 0) {
            return str;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes("ISO-8859-1"));
        GZIPInputStream gunzip = new GZIPInputStream(in);
        byte[] buffer = new byte[256];
        int n;
        while ((n = gunzip.read(buffer)) >= 0) {
            out.write(buffer, 0, n);
        }
        // toString()使用平台默认编码,也可以显式的指定如toString("GBK")
        return out.toString();
    }
str.getBytes("ISO-8859-1"),我就尝试转换了一下

$content = mb_convert_encoding($data, 'ISO-8859-1', 'utf-8');
var_dump(json_decode(urldecode(gzdecode($content)), true));
然后就解析成功了,现在php对接Luckysheet也可以了
990 2 0
2个回答

xiuwang

不发websocket前端代码?

  • zh7314 2022-09-02

    怀疑是socket通信的时候,接受的数据有问题

  • meows 2022-09-02

    你发的截图,它本身一个Http 请求?

xiuwang

我觉得可能是你前端代码问题,你没发websocket前端代码,所以问你前端代码在哪?结果你还是没贴...

我测试没问题

process/Ws.php

<?php
namespace process;

class Ws
{
    public function onMessage($con, $data)
    {
        var_export(json_decode(urldecode(gzdecode($data)), true));
    }
}

config/process.php

<?php
return [
    'ws' => [
        'handler' => \process\Ws::class,
        'listen' => 'websocket://0.0.0.0:1234'
    ]
];

前端代码

const obj = [
  { foo: 'bar', baz: 'baz' },
  { abra: 1, cadabra: 22222222222222222 }
]
let result = pako.gzip(encodeURIComponent(JSON.stringify(obj)), { to: "string" });
ws = new WebSocket('ws://127.0.0.1:1234');
ws.onopen = function(){
   ws.send(result);
}

打印结果
截图

  • 暂无评论
年代过于久远,无法发表回答
🔝