无法支持使用 ColdFusion 生成的 XML 文件中的非 UTF-8 字符

Unable to support non-UTF-8 characters in XML file generated with ColdFusion

当我 运行 服务器上的以下代码 运行ning ColdFusion 2018:

<cfsetting enablecfoutputonly="yes">

<cfxml variable="test">
    <cfoutput>
        <test>
            áéíóú
        </test>
    </cfoutput>
</cfxml>

<cfset testString = ToString(test)>

<cfset testStringISO = Replace(testString, "UTF-8", "iso-8859-1")>

<cffile action="write" file="#AbsoluteFilesPath#test.xml" output="#testStringISO#" charset="iso-8859-1">

其中 AbsoluteFilesPath 是对服务器上某个位置的绝对引用。找到了我用来更改 XML 编码的方法 here。当我在服务器上用 Notepad++ 打开 test.xml 文件时,它看起来像这样:

<?xml version="1.0" encoding="iso-8859-1"?>
<test>
    αινσϊ
</test>

文件的编码显示为“ISO 8859-7”。

有趣的是,在我的本地机器上用 VSCode 打开文件显示如下:

<?xml version="1.0" encoding="iso-8859-1"?>
<test>
    �����
</test>

这里,文件的编码显示为“UTF-8”。在编辑器中选择命令“使用编码 ISO 8859-1 重新打开”显示文件应该是这样的:

<?xml version="1.0" encoding="iso-8859-1"?>
<test>
    áéíóú
</test>

我测试了这段代码,将“iso-8859-1”替换为“utf-16”,结果是一样的。

为什么文件编码不一致,不是我想要的?如何确保使用正确的编码创建文件?

让我们先澄清一点:XML 文件中的 encoding 属性只是 reader 的一个指标。它不影响写入实际文件的字节。

所以让我们将示例代码简化为单个字符 á:

UTF-8 存储 2 个字节,ISO-8859-1 存储 1 个字节。这就是我们所期望的。

示例代码

<cfsetting enablecfoutputonly="true">

<cfxml variable="test">
    <cfoutput><r>á</r></cfoutput>
</cfxml>

<cfset xmlForUTF = toString(test)>
<cfset xmlForISO = replace(xmlForUTF, 'encoding="UTF-8"', 'encoding="ISO-8859-1"')>

<cfset fileWrite(expandPath("UTF-8.xml"),      xmlForUTF, "UTF-8")>
<cfset fileWrite(expandPath("ISO-8859-1.xml"), xmlForISO, "ISO-8859-1")>

生成的文件

UTF-8.xml

ISO-8859-1.xml

这正是我们所期望的。 cfxmlcffile/fileWrite 都不是问题。 那么为什么在您的机器上使用上述代码可能得不到相同的结果?

问题:页面编码

ColdFusion在解析模板文件(.cfm)和组件文件(.cfc)时,会使用JVM的默认编码,如无特别说明,即为系统默认编码。这也是为什么每个人用上面的代码得到不同结果的原因。

如果文件中有诸如 á 之类的文字,则此字符将使用您告诉文本编辑器使用的任何内容进行编码。我们假设是 UTF-8。如果您检查该文件,您将看到该字符已正确存储。然而,当 ColdFusion 打开这个文件并解析文字时,它会假定该字符使用系统的默认编码进行编码。不幸的是,您似乎 运行 一个不使用或不能使用 UTF-8 作为系统范围代码集的系统(例如 Windows)。

解决方案

一种(丑陋的)解决方法

cfprocessingdirective

解决它的(hacky)方法

将 ColdFusion 使用其解析器处理的每个文件(所有 .cfm/.cfc 文件)保存为 UTF-8 BOM。当 ColdFusion 在文件开头遇到这些字节时,它会被迫使用 UTF-8,因为这是 BOM 的含义。

解决问题的全局方法

-Dfile.encoding=UTF-8 添加到您的 ColdFusion JVM。可以在此处添加参数:/cfusion/bin/jvm.config(行:java.args=

这需要重新启动 ColdFusion 才能恢复。然后,您的所有文件都可以保存为简单的 UTF-8(无 BOM)格式,这样就可以正常工作了。