Tcl脚本通过Web执行插入MariaDB时UTF-8字符错误求助
问题描述
运行Rocky Linux(CentOS也存在同样问题),环境为Apache 2.4.53 + MariaDB(mysql Ver 8.0.30 for Linux on x86_64 (Source distribution))。
编写了一个Tcl脚本,通过curl获取其他站点的JSON数据,经JSON包解析后插入数据库,执行语句示例:
insert into table set name='Mário Flores';
其中包含UTF-8字符“á”。数据库已设置为utf8mb4字符集,系统区域设置为en_US.UTF-8,所有配置均正确。
脚本在Linux本地执行时无任何问题,但通过网站按钮POST到web服务器(index.cgi)执行时,出现错误:
Error: mysqlexec/db server: Incorrect string value: '\xE1rio...' for column 'name' at row 1
两种场景执行的是同一代码,目前仅能通过在Web执行时添加以下代码解决:
set name [encoding convertto utf-8 $name]
原本预期所有内容已兼容UTF-8,无需转换,想请教问题根源是什么?
问题根源分析
- CGI环境与本地环境的Tcl编码默认值差异:Tcl的字符串编码处理依赖运行环境的locale配置。本地执行时,系统locale为
en_US.UTF-8,Tcl会自动将字符串标记为UTF-8编码;但Apache的CGI进程默认可能未继承完整的系统locale,导致Tcl把字符串当作**ISO-8859-1(Latin-1)**编码处理。错误信息中的\xE1正是“á”在ISO-8859-1中的单字节值,而数据库期望的是UTF-8的双字节\xC3\xA1,因此插入时触发编码不匹配错误。 - JSON解析后的编码标识缺失:在CGI环境下,Tcl解析JSON后得到的字符串没有被正确标记为UTF-8编码,导致字符串以原生字节流的形式被数据库驱动发送;而本地执行时,系统locale让Tcl自动为字符串补上UTF-8编码标记,数据库能正确识别。
- Apache CGI的环境变量重置:本地shell环境中
LC_ALL、LANG等变量明确为en_US.UTF-8,但Apache启动CGI进程时可能重置了这些变量(比如设为C或空值),导致Tcl无法自动启用UTF-8编码支持。
总结
本质是CGI环境与本地shell环境的locale/编码默认配置不一致,导致Tcl对字符串的编码处理逻辑发生变化。添加encoding convertto utf-8相当于强制为字符串补上UTF-8编码标记,让数据库驱动能正确识别并发送符合要求的字节流。
内容的提问来源于stack exchange,提问作者Miguel Frias
相关产品推荐
相关产品推荐

