Rails用\ u0022字符失败解码json

时间:2016-05-26 14:59:29

标签: ruby-on-rails ruby json utf-8

我想解码一个带有\u0022字符的json字符串。

我成功了:

>> ActiveSupport::JSON.decode("{\"json\":{\"difficulty\":1}}")
=> {"json"=>{"difficulty"=>1}}

但失败了:

>> ActiveSupport::JSON.decode("{\"json\":{\"difficulty\":\"test\\u0022test\"}}")
StandardError: Invalid JSON string
from /home/.../.rbenv/versions/1.8.7-p358/lib/ruby/gems/1.8/gems/activesupport-2.3.15/lib/active_support/json/backends/yaml.rb:14:in `decode'
from /home/.../.rbenv/versions/1.8.7-p358/lib/ruby/gems/1.8/gems/activesupport-2.3.15/lib/active_support/json/decoding.rb:14:in `__send__'
from /home/.../.rbenv/versions/1.8.7-p358/lib/ruby/gems/1.8/gems/activesupport-2.3.15/lib/active_support/json/decoding.rb:14:in `decode'
from (irb):11

我希望将\u0022字符替换为另一个字符,但我不能这样做,因为当应用程序收到请求时,它会在rails的参数解析过程中进行;除非我覆盖了json decode chore方法,我宁愿避免这种方法。

仅供参考:我在Ruby 1.8.7-p358& Rails 2.3.15&我不能改变它。

1 个答案:

答案 0 :(得分:0)

我认为这与Syck有关,Syck是(非常)旧版Ruby中使用的旧YAML库。这与YAML有什么关系?在ActiveSupport 2.3.15中,JSON解码使用YAML.load来解析JSON,因为JSON恰好是YAML的子集。

快速搁置:在ActiveSupport 2.3.18中,ActiveSupport :: JSON :: Backends :: Yaml不再使用YAML后端解码YAML,ActiveSupport::JSON::Backends::Yaml#decode如下所示:

def decode(json)
  raise "The Yaml backend has been deprecated due to security risks, you should set ActiveSupport::JSON.backend = 'OkJson'"
end

使用过时版本的Ruby和Rails会产生非常严重的后果。升级到安全版本仍然支持的版本,否则您会感到抱歉。严重。

无论如何,让我们仔细看看你的数据。我怀疑你知道,UTF-8字符U+0022 is a double-quote。所有的转义让事情变得混乱,所以让我们看看我们实际拥有的字符串:

str = "{\"json\":{\"difficulty\":\"test\\u0022test\"}}"
puts str
# => {"json":{"difficulty":"test\u0022test"}}

FWIW在这里使用Ruby的替代字符串语法更具可读性,例如:

str = %Q[{"json":{"difficulty":"test\\u0022test"}}]
puts str
# => {"json":{"difficulty":"test\u0022test"}}

无论哪种方式,文字\后跟u0022。到现在为止还挺好。现在让我们尝试用Syck解析它(我使用的是Ruby 2.2,但在这种情况下并没有什么区别):

require "syck"

str = %Q[{"json":{"difficulty":"test\\u0022test"}}]
Syck.load(str)
# => .../syck.rb:145:in `load': syntax error on line 0, col 38: `# Transforms the subclass name found i}}' (ArgumentError)

我不知道Syck的错误消息为何如此奇怪,但无论如何我们都可以看到Syck试图解析这个JSON。现在让我们用现代的YAML解析器来尝试它:

require "psych"

str = %Q[{"json":{"difficulty":"test\\u0022test"}}]
Psych.load(str)
# => {"json":{"difficulty":"test\u0022test"}}

效果很好!

所以你有几个选择。

  1. 您可以升级到仍然维护的Ruby版本,没有安全漏洞,并且有一个没有破坏的YAML解析器。

  2. 您可以升级到仍然维护的Rails版本,没有安全漏洞,并且没有使用损坏的YAML解析器来解析JSON。

  3. 您可以安装Psych,它可以作为旧版Ruby的宝石。