我在Redis中有一条短信队列。假设Redis中的消息是这样的:

"niño"

(发现非标准字符)。

Rails应用程序显示消息队列。当我在本地测试(Rails 3.2.2,Ruby 1.9.3)时,一切都很好,但是在Heroku cedar(Rails 3.2.2,我相信有ruby 1.9.2)上,我得到了臭名昭著的错误:ActionView::Template::Error (invalid byte sequence in UTF-8)
阅读并重新阅读了所有可以在网上找到的信息后,我仍然对如何解决此问题感到困惑。

任何帮助或指出正确的方向,我们将不胜感激!

编辑:

我设法找到一个解决方案。我最终使用了Iconv:
string = Iconv.iconv('UTF-8', 'ISO-8859-1', message)[0]

我发现的建议答案似乎都不适合我的情况。

最佳答案

在Heroku上,当您的应用程序从Redis收到消息“niño”时,实际上是在获取四个字节:

 0x6e 0x69 0xf1 0x6f

当被解释为ISO-8859-1时,它对应于字符niño

但是,您的Rails应用假定这些字节应解释为UTF-8,并在某些时候尝试以此方式对其进行解码。此序列中的第三个字节0xf1如下所示:

1 1 1 1 0 0 0 1

如果将此与table on the Wikipedia page进行比较,则可以看到此字节是四个字节字符的前导字节(它与11110xxx模式匹配),因此应在其后跟随三个都与10xxxxxx模式匹配的继续字节。不是,下一个字节是0x6f(01101111),因此这是无效的utf-8字节序列,您会看到错误。

使用:
string = message.encode('utf-8', 'iso-8859-1')

(或等效的Iconv)告诉Ruby以ISO-8859-1编码读取message,然后以UTF-8编码创建等效的字符串,然后可以毫无问题地使用它。 (一种替代方法是使用 force_encoding 告诉Ruby字符串的正确编码,但是稍后尝试混合UTF-8和ISO-8859-1字符串时,可能会导致问题。)

在UTF-8中,字符串“niño”对应于以下字节:

0x6e 0x69 0xc3 0xb1 0x6f

请注意,第一个,第二个和最后一个字节是相同的。 ñ字符被编码为两个字节0xc3 0xb1。如果将它们写成二进制并再次与Wikipedia中的表进行比较,您会看到它们编码为0xf1,这是ñ的ISO-8859-1编码(因为前256个unicode码点与ISO-8859-1匹配) 。

如果您将这五个字节当作ISO-8859-1对待,那么它们对应于字符串
niño

查看ISO-8859-1 codepage,0xc3映射到Â,0xb1映射到±

因此,本地计算机上发生的事情是您的应用程序正在从Redis接收五个字节的0x6e 0x69 0xc3 0xb1 0x6f,这是“niño”的UTF-8表示形式。在Heroku上,它接收四个字节的0x6e 0x69 0xf1 0x6f,即ISO-8859-1表示形式。

解决您的问题的真正方法是确保放入Redis的字符串已经全部为UTF-8(或至少所有相同的编码)。我还没有使用过Redis,但是从简短的Google可以看出,它本身与字符串编码无关,而只是返回给定的任何字节。您应该查看将数据放入Redis的任何过程,并确保其正确处理了编码。

关于ruby-on-rails - Rails,Heroku和UTF-8错误中的无效字节序列,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10046469/

10-09 20:05
查看更多