Nodejs进阶之服务端字符编解码和乱码处理


Posted in NodeJs onSeptember 04, 2017

写在前面

在web服务端开发中,字符的编解码几乎每天都要打交道。编解码一旦处理不当,就会出现令人头疼的乱码问题。

不少从事node服务端开发的同学,由于对字符编码码相关知识了解不足,遇到问题时,经常会一筹莫展,花大量的时间在排查、解决问题。

文本先对字符编解码的基础知识进行简单介绍,然后举例说明如何在node中进行编解码,最后是服务端的代码案例。本文相关代码示例可在这里找到。

关于字符编解码

在网络通信的过程中,传输的都是二进制的比特位,不管发送的内容是文本还是图片,采用的语言是中文还是英文。

举个例子,客户端向服务端发送"你好"。

客户端 --- 你好 ---> 服务端

这中间包含了两个关键步骤,分别对应的是编码、解码。

1.客户端:将"你好"这个字符串,编码成计算机网络需要的二进制比特位。

2.服务端:将接收到的二进制比特位,解码成"你好"这个字符串。

总结一下:

1.编码:将需要传送的数据,转成对应的二进制比特位。

2.解码:将二进制比特位,转成原始的数据。

上面有些重要的技术细节没有提到,答案在下一小节。

  • 客户端怎么知道"你好"这个字符对应的比特位是多少?
  • 服务端收到二进制比特位之后,怎么知道对应的字符串是什么?

关于字符集和字符编码

上面提到字符、二进制的转换问题。既然两者可以互相转换,也就是说存在明确的转换规则,可以实现字符<->二进制的相互转换。

这里提到的转换规则,其实就是我们经常听到的字符集&字符编码。

字符集是一系列字符(文字、标点符号等)的集合。字符集有很多,常见的有ASCII、Unicode、GBK等。不同字符集主要的区别在于包含字符个数的不同。

了解了字符集的概念后,接下来介绍下字符编码。

字符集告诉我们支持哪些字符,但具体字符怎么编码,是由字符编码决定的。比如Unicode字符集,支持的字符编码有UTF8(常用)、UTF16、UTF32。

概括一下:

  • 字符集:字符的集合,不同字符集包含的字符数不同。
  • 字符编码:字符集中字符的实际编码方式。
  • 一个字符集可能有多种字符编码方式。

可以把字符编码看成一个映射表,客户端、服务端就是根据这个映射表,来实现字符跟二进制的编解码转换。

举个例子,"你"这个字符,在UTF8编码中,占据三个字节0xe4 0xbd 0xa0,而在GBK编码中,占据两个字节0xc4 0xe3。

字符编解码例子

上面已经提到了字符编解码所需的基础知识。下面我们看一个简单的例子,这里借助了icon-lite这个库来帮助我们实现编解码的操作。

可以看到,在字符编码时,我们采用了gbk。在解码时,如果同样采用gbk,可以得到原始的字符。而当我们解码时采用utf8时,则出现了乱码。

var iconv = require('iconv-lite');

var oriText = '你';

var encodedBuff = iconv.encode(oriText, 'gbk');
console.log(encodedBuff);
// <Buffer c4 e3>

var decodedText = iconv.decode(encodedBuff, 'gbk');
console.log(decodedText);
// 你

var wrongText = iconv.decode(encodedBuff, 'utf8');
console.log(wrongText);
// ��

实际例子:服务端编解码

通常我们需要处理编解码的场景有文件读写、网络请求处理。这里距网络请求的例子,介绍如何在服务端进行编解码。

假设我们运行着如下http服务,监听来自客户端的请求。客户端传输数据时采用了gbk编码,而服务端默认采用的是utf8编码。

如果此时采用默认的utf8对请求进行解码,就会出现乱码,因此需要特殊处理。

服务端代码如下(为简化代码,这里跳过了请求方法、请求编码的判断)

var http = require('http');
var iconv = require('iconv-lite');

// 假设客户端采用post方法,编码为gbk
var server = http.createServer(function (req, res) {
  var chunks = [];
  
  req.on('data', function (chunk) {
    chunks.push(chunk)
  });

  req.on('end', function () {
    chunks = Buffer.concat(chunks);

    // 对二进制进行解码
    var body = iconv.decode(chunks, 'gbk');
    console.log(body);

    res.end('HELLO FROM SERVER');
  });

});

server.listen(3000);

对应的客户端代码如下:

var http = require('http');
var iconv = require('iconv-lite');

var charset = 'gbk';

// 对字符"你"进行编码
var reqBuff = iconv.encode('你', charset);

var options = {
  hostname: '127.0.0.1',
  port: '3000',
  path: '/',
  method: 'POST',
  headers: {
    'Content-Type': 'text/plain',
    'Content-Encoding': 'identity',
    'Charset': charset // 设置请求字符集编码
  }
};

var client = http.request(options, function(res) {
  res.pipe(process.stdout);
});

client.end(reqBuff);

相关链接

Nodejs学习笔记:https://github.com/chyingp/nodejs-learning-guide

iconv-lite:https://github.com/ashtuchkin/iconv-lite

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
nodejs文件操作模块FS(File System)常用函数简明总结
Jun 05 NodeJs
NodeJS中Buffer模块详解
Jan 07 NodeJs
nodejs中使用多线程编程的方法实例
Mar 24 NodeJs
Nodejs如何复制文件
Mar 09 NodeJs
nodejs简单实现操作arduino
Sep 25 NodeJs
nodeJs链接Mysql做增删改查的简单操作
Feb 04 NodeJs
NodeJS实现图片上传代码(Express)
Jun 30 NodeJs
nodejs模块学习之connect解析
Jul 05 NodeJs
深入学习nodejs中的async模块的使用方法
Jul 12 NodeJs
Linux Centos7.2下安装nodejs&amp;npm配置全局路径的教程
May 15 NodeJs
nodejs实现范围请求的实现代码
Oct 12 NodeJs
PHPStorm中如何对nodejs项目进行单元测试详解
Feb 28 NodeJs
Windows下使用Nodejs运行js的方法
Sep 02 #NodeJs
用nodejs实现json和jsonp服务的方法
Aug 25 #NodeJs
NodeJS收发GET和POST请求的示例代码
Aug 25 #NodeJs
Nodejs 和Session 原理及实战技巧小结
Aug 25 #NodeJs
Nodejs 复制文件/文件夹的方法
Aug 24 #NodeJs
使用Nodejs连接mongodb数据库的实现代码
Aug 21 #NodeJs
nodejs动态创建二维码的方法
Aug 12 #NodeJs
You might like
PHP树的代码,可以嵌套任意层
2006/10/09 PHP
header导出Excel应用示例
2014/01/24 PHP
PHP获取浏览器信息类和客户端地理位置的2个方法
2014/04/24 PHP
Zend Guard使用指南及问题处理
2015/01/07 PHP
微信封装的调用微信签名包的类库
2017/06/08 PHP
php中curl和soap方式请求服务超时问题的解决
2018/06/11 PHP
PHP+Redis开发的书签案例实战详解
2019/07/09 PHP
用javascript实现的图片马赛克后显示并切换加文字功能
2007/04/21 Javascript
ASP 过滤数组重复数据函数(加强版)
2010/05/31 Javascript
js拖拽一些常见的思路方法整理
2014/03/19 Javascript
jquery 自定义容器下雨效果可将下雨图标改为其他
2014/04/23 Javascript
JS+CSS实现淡入式焦点图片幻灯切换效果的方法
2015/02/26 Javascript
jQuery实现页面内锚点平滑跳转特效的方法总结
2015/05/11 Javascript
JS中的THIS和WINDOW.EVENT.SRCELEMENT详解
2015/05/25 Javascript
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
2017/03/06 Javascript
JavaScript实现写入文件到本地的方法【基于FileSaver.js插件】
2018/03/15 Javascript
基于vue和react的spa进行按需加载的实现方法
2018/09/29 Javascript
详解javascript 变量提升(Hoisting)
2019/03/12 Javascript
微信小程序授权登录解决方案的代码实例(含未通过授权解决方案)
2019/05/10 Javascript
JS实现滑动导航效果
2020/01/14 Javascript
Vue v-bind动态绑定class实例方法
2020/01/15 Javascript
JavaScript实现PC端四格密码输入框功能
2020/02/19 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
2020/11/11 Javascript
[57:09]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第一场 1月26日
2021/03/11 DOTA
Python中基本的日期时间处理的学习教程
2015/10/16 Python
python 函数传参之传值还是传引用的分析
2017/09/07 Python
Python下使用Scrapy爬取网页内容的实例
2018/05/21 Python
Python 模拟动态产生字母验证码图片功能
2019/12/24 Python
python解压zip包中文乱码解决方法
2020/11/27 Python
DOM和JQuery对象有什么区别
2016/11/11 面试题
最经典的商业地产项目广告词
2014/03/13 职场文书
小学教师先进事迹材料
2014/12/15 职场文书
2015年前台接待工作总结
2015/05/04 职场文书
家长会感言
2015/08/01 职场文书
原生JS封装vue Tab切换效果
2021/04/28 Vue.js
速龙x4-860k处理器相当于i几
2022/04/20 数码科技