所以我在 GitHub 上 fork 了这个 gem,认为我可以修复和更新它的一些问题以便在 Rails 项目中使用。我基本上得到了这个输出:
irb(main):020:0> query = Query::simpleQuery('xx.xxx.xxx.xx', 25565)
=> [false, #<Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ASCII-8BIT>]
irb(main):021:0> query = Query::simpleQuery('xx.xxx.xxx.xx', 25565)
=> {:motd=>"Craftnet", :gametype=>"SMP", :map=>"world", :numplayers=>"0", :maxplayers=>"48"}
第一个响应是编码错误的示例,第二个是想要的输出(IP 的取出)。基本上这是在 Minecraft 服务器上查询有关它的信息。
我试过用
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
但这只是给出了相同的响应,随机吐出编码错误而不是。
这是包含所有代码的相关 GitHub 存储库:RubyMinecraft
如有任何帮助,我们将不胜感激。
最佳答案
在 Query
类中有 this line :
@key = Array(key).pack('N')
这将创建一个带有关联编码 ASCII-8BIT 的字符串(即它是一个二进制字符串)。
稍后 @key
被用于 this line :
query = @sock.send("\xFE\xFD\x00\x01\x02\x03\x04" + @key, 0)
在 Ruby 2.0 中,字符串文字的默认编码是 UTF-8,因此这是将 UTF-8 字符串与二进制字符串组合在一起。
当 Ruby 尝试这样做时,它首先检查二进制字符串是否只包含 7 位值(即所有字节都小于或等于 127,最高字节为 0),如果是,它会考虑它与 UTF-8 兼容,因此可以毫无问题地将它们结合起来。如果不是,(即,如果它包含大于 127 的字节)那么这两个字符串不兼容,并引发 Encoding::CompatibilityError
。
是否引发错误取决于 @key
的内容,它是从服务器的响应中初始化的。有时这个值恰好只包含 7 位值,因此不会引发错误,有时会有一个字节设置了高位,因此会产生错误。这就是为什么错误看起来是“随机的”。
要修复它,您可以指定将两个字符串组合的行中的字符串文字视为二进制。最简单的方法是使用 force_encoding
像这样:
query = @sock.send("\xFE\xFD\x00\x01\x02\x03\x04".force_encoding(Encoding::ASCII_8BIT) + @key, 0)
关于ruby-on-rails - Ruby Gem 随机返回编码错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17627269/