JavaScript将Unicode转换为GBK并通过http POST给服务器

中文与GBK

GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification),GBK 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1国际标准,是前者向后者过渡过程中的一个承上启下的产物。ISO 10646 是国际标准化组织 ISO 公布的一个编码标准,即 Universal Multilpe-Octet Coded Character Set(简称UCS),大陆译为《通用多八位编码字符集》,台湾译为《广用多八位元编码字元集》,它与 Unicode 组织的 Unicode 编码完全兼容。

GBK编码,是在GB2312-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准,支持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。GBK编码方案于1995年10月制定, 1995年12月正式发布。

能显示中文的嵌入式设备,一般都支持GB2312,GB2312有很多适合小设备的优点:1)7000多汉字,基本覆盖常用生活场景;2)2字节编码,节省存储空间;3)向上兼容GBK。嵌入式设备一般能力有限,无法进行字符集的转码工作。

本文关注在嵌入式设备场景,嵌入式设备通过WiFi或者Ethernet提供一个小型的http服务器,用户通过PC或者手机的浏览器访问,并进行一些与汉字相关的配置操作。因为涉及到修改名称等直接与汉字有关的内容,因此,需要用到GBK编码的转换,简单说,当设备提供网页上要显示的内容时,设备内的httpd服务器提供GBK编码的内容(JSON)给浏览器,浏览器前端页面需要将GBK编码内容提取、转码后渲染页面(Unicode);当用户在页面编辑好汉字后,还需要将Unicode转码为GBK,返回给设备进行存储。

GBK转成Unicode

思路:访问服务器接口后,得到的JSON串(GBK编码)用blob格式转出,然后用FileReader来读取,读取时采用GBK编码格式处理。

 
            fetch(`${baseHost}/status`)
                .then(res => {
                    return res.blob();
                })
                .then(data => {
                    let reader = new FileReader();
                    reader.onload = () => {
                        const text = reader.result;
                        // console.log("返回:", text);
                        statusData = JSON.parse(text);
                        updateUI();   // 用收到的json内容更新UI
                        setData();     // 用收到的json内容更新控件
                    };
                    reader.readAsText(data, "gbk");
                })
                .catch(e => {
                    console.log(e);
                });
 

Unicode转成GBK

思路:用户修改页面内容后,变量生成的JSON串(Unicode编码)转码为GBK格式Uint8Array,然后将Uint8Array用blob格式转出,并直接以二进制内容通过POST方式发回http服务器。

其中Unicode转GBK采用的查表方式,没有使用任何现有的转码方式,降低了对浏览器的依赖。使用TextDecoder('gbk')方法生成GBK码表,具体原理可以参考:

《JS 中转 GBK 编码字符串超简实现》

       
        // 转码方法
        function stringToGbk(str) {
            const ranges = [
                [0xA1, 0xA9, 0xA1, 0xFE],
                [0xB0, 0xF7, 0xA1, 0xFE],
                [0x81, 0xA0, 0x40, 0xFE],
                [0xAA, 0xFE, 0x40, 0xA0],
                [0xA8, 0xA9, 0x40, 0xA0],
                [0xAA, 0xAF, 0xA1, 0xFE],
                [0xF8, 0xFE, 0xA1, 0xFE],
                [0xA1, 0xA7, 0x40, 0xA0],
            ]
            const codes = new Uint16Array(23940)
            let i = 0

            for (const [b1Begin, b1End, b2Begin, b2End] of ranges) {
                for (let b2 = b2Begin; b2 <= b2End; b2++) {
                    if (b2 !== 0x7F) {
                        for (let b1 = b1Begin; b1 <= b1End; b1++) {
                            codes[i++] = b2 << 8 | b1
                        }
                    }
                }
            }
            const cstr = new TextDecoder('gbk').decode(codes)

            // 编码表
            const table = new Uint16Array(65536)
            for (let i = 0; i < cstr.length; i++) {
                table[cstr.charCodeAt(i)] = codes[i]
            }
            const buf = new Uint8Array(str.length * 2)
            let n = 0

            for (let i = 0; i < str.length; i++) {
                const code = str.charCodeAt(i)
                if (code < 0x80) {
                    buf[n++] = code
                } else {
                    const gbk = table[code]
                    buf[n++] = gbk & 0xFF
                    buf[n++] = gbk >> 8
                }
            }
            u8buf = buf.subarray(0, n)
            // console.log(u8buf);
            return u8buf
        }
 
            // 发送给http服务器,注意不需要添加Content-Type
            // 将对象生成json(unicode格式)
            const input = JSON.stringify(statusData, null, 0)
            // 转码为GBK格式Uint8Array
            let u8buf = stringToGbk(input);
            // console.log(u8buf)
            // GBK格式Uint8Array转为blob文件对象
            const blob = new Blob([u8buf], {type: 'application/octet-stream'});
            // 发送POST请求
            fetch(`${baseHost}/save`, {
                method: "post",
                body: blob
            })
 

欢迎转载,本文地址: https://blog.prodrich.com/detail/84/

带着使命来到世上的你,给他人提供价值,才有价值