JSON 编码错误转义(Rails 3、Ruby 1.9.2)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5123993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JSON encoding wrongly escaped (Rails 3, Ruby 1.9.2)
提问by Michiel de Mare
In my controller, the following works (prints "oké")
在我的控制器中,以下工作(打印“oké”)
puts obj.inspect
But this doesn't (renders "ok\u00e9")
但这不是(呈现“ok\u00e9”)
render :json => obj
Apparently the to_jsonmethod escapes unicode characters. Is there an option to prevent this?
显然,该to_json方法会转义 unicode 字符。有没有办法防止这种情况发生?
采纳答案by mu is too short
If you dig through the source you'll eventually come to ActiveSupport::JSON::Encodingand the escapemethod:
如果你挖通了源,你最终会来ActiveSupport::JSON::Encoding和escape方法:
def escape(string)
if string.respond_to?(:force_encoding)
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
end
json = string.
gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
gsub(/([\xC0-\xDF][\x80-\xBF]|
[\xE0-\xEF][\x80-\xBF]{2}|
[\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\u\&')
}
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
json
end
The various gsubcalls are forcing non-ASCII UTF-8 to the \uXXXXnotation that you're seeing. Hex encoded UTF-8 should be acceptable to anything that processes JSON but you could always post-process the JSON (or monkey patch in a modified JSON escaper) to convert the \uXXXXnotation to raw UTF-8 if necessary.
各种gsub调用将非 ASCII UTF-8 强制转换为\uXXXX您所看到的符号。十六进制编码的 UTF-8 应该可以被任何处理 JSON 的东西所接受,但您可以随时对 JSON(或修改后的 JSON 转义器中的猴子补丁)进行后处理,\uXXXX以在必要时将表示法转换为原始 UTF-8。
I'd agree that forcing JSON to be 7bit-clean is a bit bogus but there you go.
我同意强制 JSON 为 7bit-clean 有点虚假,但你去了。
Short answer: no.
简短的回答:没有。
回答by Wouter Vegter
To set the \uXXXX codes back to utf-8:
要将 \uXXXX 代码设置回 utf-8:
json_string.gsub!(/\u([0-9a-z]{4})/) {|s| [.to_i(16)].pack("U")}
回答by David Backeus
You can prevent it by monkey patching the method mentioned by muu is too short. Put the following into config/initializers/patches.rb (or similar file used for patching stuff) and restart your rails process for the change to take affect.
你可以通过猴子修补 muu 提到的方法来防止它太短。将以下内容放入 config/initializers/patches.rb(或用于修补内容的类似文件)并重新启动 Rails 进程以使更改生效。
module ActiveSupport::JSON::Encoding
class << self
def escape(string)
if string.respond_to?(:force_encoding)
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
end
json = string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] }
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
json
end
end
end
Be adviced that there's no guarantee that the patch will work with future versions of ActiveSupport. The version used when writing this post is 3.1.3.
请注意,不能保证该补丁适用于 ActiveSupport 的未来版本。写这篇文章时使用的版本是 3.1.3。
回答by oldergod
Characters were not escaped to unicode with the other methods in Rails2.3.11/Ruby1.8so I used the following:
字符没有使用其他方法转义为 unicode,Rails2.3.11/Ruby1.8所以我使用了以下内容:
render :json => JSON::dump(obj)
回答by Ben Blank
That is the correct encoding. JSON doesn't requreUnicode characters to be escaped, but it is common for JSON libraries to produce output which contains only 7-bit ASCII characters, to avoid any potential encoding problems in transit.
那是正确的编码。JSON 不需要转义Unicode 字符,但 JSON 库通常会生成仅包含 7 位 ASCII 字符的输出,以避免在传输过程中出现任何潜在的编码问题。
Any JSON interpreter will be able to consume that string and reproduce the original. To see this in action, just type javascript:alert("ok\u00e9")into your browser's location bar.
任何 JSON 解释器都可以使用该字符串并重现原始字符串。要查看此操作,只需javascript:alert("ok\u00e9")在浏览器的位置栏中输入即可。
回答by patrick
render :json will call .to_json on the object if it's not a string. You can avoid this problem by doing:
如果对象不是字符串, render :json 将在对象上调用 .to_json 。您可以通过执行以下操作来避免此问题:
render :json => JSON.generate(obj)
This will by pass a string directly and therefore avoid the call to ActiveSupport's to_json.
这将直接传递一个字符串,因此避免调用 ActiveSupport 的 to_json。
Another approach would be to override to_json on the object you are serializing, so in that case, you could do something like:
另一种方法是在您正在序列化的对象上覆盖 to_json,因此在这种情况下,您可以执行以下操作:
class Foo < ActiveRecord::Base
def to_json(options = {})
JSON.generate(as_json)
end
end
And if you use ActiveModelSerializers, you can solve this problem by overriding to_json in your serializer:
如果你使用 ActiveModelSerializers,你可以通过在序列化器中覆盖 to_json 来解决这个问题:
# controller
respond_with foo, :serializer => MySerializer
# serializer
attributes :bar, :baz
def to_json(options = {})
JSON.generate(serializable_hash)
end
回答by Yitong Zhou
I have got a very tricky way to solve this problem. Well, if to_jsondid not allow you to have the correct code, then you could directly try to write :
我有一个非常棘手的方法来解决这个问题。好吧,如果to_json不允许你有正确的代码,那么你可以直接尝试写:
render text: tags
render json: tagsor render json: tags.to_jsonwill always auto transfer the encoding style, but if you use render text:tags, then the string will stay as it is. And I think jQuery could still recognize the data.
render json: tags或render json: tags.to_json将始终自动传输编码样式,但如果您使用render text:tags,则字符串将保持原样。而且我认为 jQuery 仍然可以识别数据。

