Bootstrap

Node.js 中文编码问题全解析

Node.js 中文编码问题全解析

问题背景

在 Node.js 中执行 Gradle 命令时遇到中文输出乱码问题。这个问题涉及 Windows 系统、Java 进程和 Node.js 三个层面的编码处理。

问题分析

最初的错误代码

gradleProcess.stdout.setEncoding('utf-8');  // 错误:假设输出是 UTF-8 编码
gradleProcess.stdout.on('data', (data) => {
    console.log(`Gradle ${taskName}: ${data}`);
});

为什么会乱码?

  1. Windows 系统默认使用 GBK(CP936) 编码
  2. Gradle/Java 进程输出采用系统默认编码(GBK)
  3. Node.js 默认使用 UTF-8
  4. 当用 UTF-8 解码 GBK 编码的数据时,就会出现乱码

尝试过的解决方案

方案1:设置进程编码

const process = spawn(cmd, args, { encoding: 'utf-8' });  // 不起作用

方案2:设置环境变量

env: {
    JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8",
    GRADLE_OPTS: "-Dfile.encoding=UTF-8"
}  // 不完全解决

方案3:设置控制台代码页

spawn('chcp', ['65001'])  // 不能改变 Java 进程输出

最终解决方案

import iconv from 'iconv-lite';

const gradleProcess = spawn(gradleCmd, gradleArgs, {
    cwd: this._androidDir,
    stdio: 'pipe',
    shell: true,
    windowsVerbatimArguments: true
});

gradleProcess.stdout.on('data', (data: Buffer) => {
    // 使用 iconv-lite 正确解码 GBK
    const output = iconv.decode(Buffer.from(data), 'gbk').trim();
    if (output && !output.includes('Picked up JAVA_TOOL_OPTIONS')) {
        console.log(`Gradle ${taskName}: ${output}`);
    }
});

关键认识

  1. 系统层面

    • Windows 命令行默认使用 GBK 编码
    • 改变系统编码不能完全解决问题
  2. 进程层面

    • Java/Gradle 进程继承系统编码
    • 环境变量设置可能不完全生效
  3. Node.js 层面

    • Node.js 默认使用 UTF-8
    • 需要在数据流层面处理编码转换

最佳实践

  1. 保持原始数据

    • 不要直接设置流的编码
    • 保留原始 Buffer 数据
  2. 正确的编码处理

    • 使用专业的编码转换库(如 iconv-lite)
    • 明确知道源数据的编码
  3. 编码转换原则

    • 在应用层处理编码转换
    • 不要依赖系统或环境变量设置

经验总结

  1. 不要想当然设置编码
  2. 要理解系统默认编码
  3. 在正确的层面处理编码转换
  4. 使用专门的编码转换工具
  5. 测试验证编码处理结果

这个问题很好地展示了在跨平台、多进程环境下处理字符编码的复杂性,以及如何正确处理这些问题。

;