EncodeHeader()
Unicode 字符串确实存在一些已知问题:
在相邻编码字之间分割数据时,EncodeHeader() 需要考虑代码单元
基本上,MIME 编码的单词长度不能超过 75 个字符,因此长文本会被分割。但是,当对长 Unicode 字符串进行编码时,任何给定的 Unicode 字符都可以使用 1 个或多个字节进行字符集编码,并且EncodeHeader()
尚未避免错误地将两个单独字节之间的多字节字符拆分为单独的编码字(这是非法的,并且被明确禁止)RFC 2047MIME 规范)。
但是,这并不是您的示例中发生的情况。
在你的第一个例子中,'Επιστολή εκπαιδευτικο.docx'
太长而无法编码为单个 MIME 单词,因此它被分成'Επιστολή εκπαιδευτικο.doc'
'x'
子字符串,然后单独编码。对于长文本,这在 MIME 中是合法的(尽管您可能期望 Indy 将文本拆分为'Επιστολή'
' εκπαιδευτικο.doc'
相反,或者甚至'Επιστολή'
' εκπαιδευτικο'
'.doc'
。这可能是未来版本中的可能性)。仅由空格分隔的相邻 MIME 单词在解码时将连接在一起而不分隔空格,从而产生'Επιστολή εκπαιδευτικο.docx'
再次。如果服务器没有这样做,则它的解码器有缺陷(也许它正在解码为'Επιστολή εκπαιδευτικο.doc x'
反而?)。
在你的第二个例子中,'Επιστολή εκπαιδευτικ.docx'
足够短,可以编码为单个 MIME 单词。
在你的第三个例子中,'Επιστολή εκπαιδευτικ .docx'
在第二个空白(不是第一个)上被分割成'Επιστολή εκπαιδευτικ'
' .docx'
子串,并且只需要对第一个子串进行编码。这在 MIME 中是合法的。解码时,解码后的文本将与以下未编码文本连接,保留它们之间的空格,从而产生'Επιστολή εκπαιδευτικ .docx'
再次。如果服务器没有这样做,则它的解码器有缺陷(也许它正在解码为'Επιστολή εκπαιδευτικ.docx'
反而?)。
如果您通过 Indy 的 MIME 标头编码器/解码器运行这些示例文件名,它们会正确解码:
var
s: String;
begin
s := EncodeHeader('Επιστολή εκπαιδευτικο.docx', '', 'B', 'UTF-8');
ShowMessage(s); // '=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66zr8uZG9j?='#13#10' =?UTF-8?B?eA==?='
s := DecodeHeader(s);
ShowMessage(s); // 'Επιστολή εκπαιδευτικο.docx'
s := EncodeHeader('Επιστολή εκπαιδευτικ.docx', '', 'B', 'UTF-8');
ShowMessage(s); // '=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66LmRvY3g=?='
s := DecodeHeader(s);
ShowMessage(s); // 'Επιστολή εκπαιδευτικ.docx'
s := EncodeHeader('Επιστολή εκπαιδευτικ .docx', '', 'B', 'UTF-8');
ShowMessage(s); // '=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66?= .docx'
s := DecodeHeader(s);
ShowMessage(s); // 'Επιστολή εκπαιδευτικ .docx'
end;
所以问题似乎出在服务器端解码上,而不是 Indy 的客户端编码上。
话虽这么说,如果您使用的是 Indy 10 的最新版本(2011 年 11 月或更高版本),TIdFormDataField
has a HeaderEncoding
属性,默认为'B'
(base64) 在 Unicode 环境中。然而,分裂逻辑也会影响'Q'
(quoted-printable) 也一样,所以这可能对你有用,也可能不适合你(但你可以尝试一下):
with Params.AddFile('File', ceFileName.Text, '') do
begin
ContentTransfer := '';
HeaderEncoding := 'Q'; // <--- here
HeaderCharSet := 'utf-8';
end;
否则,解决方法可能是将值更改为'8'
(8 位),这有效地禁用 MIME 编码(但不是字符集编码):
with Params.AddFile('File', ceFileName.Text, '') do
begin
ContentTransfer := '';
HeaderEncoding := '8'; // <--- here
HeaderCharSet := 'utf-8';
end;
请注意,如果服务器不希望文件名使用原始 UTF-8 字节,您可能仍然会遇到问题(即,'Επιστολή εκπαιδευτικο.docx'
被解释为'Επιστολή εκπαιδευτικο.docx'
, 例如)。