CGI::Fast与to_json浏览器输出异常:相等字符串为何显示不同?
FCGI环境下JSON字符编码显示差异问题分析与解决
问题本质
代码中eq判断成立但浏览器显示不同,核心是Perl字符串编码标记与JSON处理的双重编码导致的输出差异:
- Perl内部字符串分为「字节字符串」和「Unicode字符串」两种类型,
eq判断基于码点序列而非原始字节,因此两个变量的码点一致时会判定相等。 - 浏览器显示差异则是因为输出时的字节编码处理不同,导致同一码点序列被转译为不同的显示结果。
具体原因拆解
- 源码编码未声明:你的Perl源码是UTF-8编码,但未添加
use utf8;编译指示,因此字符串字面量"öäüöä"被Perl当作字节字符串(每个UTF-8字节对应一个Latin-1码点,比如ö的UTF-8字节c3 b6被解析为码点U+00C3和U+00B6)。 - JSON模块的双重编码:
to_json函数默认将输入的码点序列编码为UTF-8字节,因此原本的Latin-1码点会被再次编码,导致ö最终被转为c3 83 c2 b6(对应显示为ö)。 - 直接赋值的字符串处理:
$strng_json2是直接写入的字节字符串,源码中的öäüöä保留了原始UTF-8字节,输出时直接发送给浏览器,用UTF-8解析就能正常显示。 - eq判断的逻辑:Perl的
eq按码点序列比较,$strng_json1(Unicode字符串)和$strng_json2(字节字符串)的码点序列完全一致,因此判定为相等。
解决方案
修改代码,让Perl正确识别UTF-8源码并避免JSON双重编码:
#!/usr/bin/perl use utf8; use JSON; use CGI::Fast; while (CGI::Fast->new) { print "Content-type: text/html; charset=utf-8\n\n"; my %array; $array{strng} = "öäüöä"; # 使用encode_json替代to_json,默认输出正确的UTF-8编码JSON my $strng_json1 = encode_json(\%array); my $strng_json2 = '{"strng":"öäüöä"}'; if ($strng_json1 eq $strng_json2) { print "\$strng_json1 and \$strng_json2 are equal <br><br>"; } print "\$strng_json1: $strng_json1 <br>"; print "\$strng_json2: $strng_json2 <br>"; }
修改说明
use utf8;:告诉Perl当前源码文件是UTF-8编码,字符串字面量会被解析为Unicode码点而非字节序列。encode_json:JSON模块专门用于生成UTF-8编码的JSON字符串,会将Unicode码点直接转为正确的UTF-8字节,彻底避免双重编码问题。
内容的提问来源于stack exchange,提问作者mrezzonico
相关产品推荐
相关产品推荐

