5

我有相当标准的 javascript/XHR 拖放文件上传代码,只是遇到了一个不幸的现实障碍。我的(Win7)桌面上有一个名为“TEST-é-TEST.txt”的文件。在 Chrome (30.0.1599.69) 中,它以 UTF-8 的文件名到达服务器,效果很好。在 Firefox (24.0) 中,文件名在到达服务器时似乎已损坏。

我不相信 Firebug/Chrome 可能会告诉我有关编码的内容,因此我检查了请求数据包的十六进制。除了非 ASCII 字符在两个浏览器中的编码确实不同之外,其他一切都是相同的:

Chrome: C3 A9 (this is the expected UTF-8 for that character)
Firefox: EF BF BD (UTF-8 "replacement character"?!)

这是一个 Firefox 错误吗?我尝试重命名文件,将 é 替换为 ó,而 Firefox 十六进制是相同的......所以这样的 mangle 看起来真的像是一个浏览器错误。(例如,如果 Firefox 混淆地发送 ISO-8859-1,而没有触摸它,我会看到一个 E9 字节,我可以在服务器端处理它,但它不应该破坏它!)

不管是什么原因,我可以在客户端或服务器端做些什么来纠正这个问题吗?如果替换字符确实被发送到服务器,那么它在那里似乎无法恢复,所以我几乎肯定需要在客户端进行。

是的,存在此代码的页面具有charset=utf-8,并且 Firefox 在 View>Character Encoding 下确认它将该页面视为 UTF-8。

此外,如果我将文件名转储到 console.log,它在那里看起来很好——我猜它只是在 /after 中被破坏了setRequestHeader("X-File-Name",file.name)

最后,似乎传递给 setRequestHeader() 的值应该能够具有高达 U+00FF 的代码点,因此 U+00E9 (é) 和 U+00F3 (ó) 不应该引起问题,尽管更高的代码可能会触发 SyntaxError:http ://www.w3.org/TR/XMLHttpRequest2/#the-setrequestheader-method

4

1 回答 1

9

非常感谢鲍里斯的帮助。以下是我通过评论中的互动发现的总结:

1) 核心问题是HTTP 请求标头应该是 ISO-8859-1。之前版本的 Chrome 和 Firefox 都在 setRequestHeader() 调用中传递 UTF-8 字符串不变。这在 FF24.0 中发生了变化(显然 Chrome 也将很快发生变化),这样 FF 会丢弃高字节并仅传递每个字符的低字节。在我在问题中给出的示例中,这是可以恢复的,但是具有更高代码的字符可能会被不可挽回地损坏。

2)一种解决方法是在客户端进行编码,例如:

setRequestHeader('X-File-Name',encodeURIComponent(filename))

然后在服务器端解码,例如在 PHP 中:

$filename=rawurldecode($_SERVER['HTTP_X_FILE_NAME'])

3)请注意,这只是有问题的,因为我的ajax文件上传方法是在请求正文中发送原始文件数据,因此我需要通过自定义请求标头发送文件名(如在线许多教程中所示)。如果我改用FormData,我就不用担心这个了。我相信如果您想要可靠的、基于标准的 unicode 文件名支持,您应该使用 FormData 而不是请求标头方法。

于 2013-10-10T15:26:20.010 回答