错误地转义了JSON编码(Rails 3,Ruby 1.9.2)
在我的控制器中,以下工作(打印“oké”)
puts obj.inspect
但这不会(呈现“ok \ u00e9”)
render :json => obj
显然, to_json
方法会转义unicode字符。 有没有办法防止这种情况发生?
如果你ActiveSupport::JSON::Encoding
源代码,你最终会得到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
各种gsub
调用正在强制非ASCII UTF-8到您所看到的\uXXXX
表示法。 hex编码的UTF-8应该是处理JSON的任何东西都可以接受的,但你总是可以对JSON(或修改过的JSON escaper中的猴子补丁)进行后处理,以便在必要时将\uXXXX
表示法转换为原始UTF-8。
我同意强制JSON为7bit-clean有点虚假但你去了。
简答:不。
要将\ uXXXX代码设置回utf-8:
json_string.gsub!(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
你可以通过猴子修补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
请注意,无法保证该补丁可以与未来版本的ActiveSupport一起使用。 撰写这篇文章时使用的版本是3.1.3。
这是正确的编码。 JSON不要求转义Unicode字符,但JSON库通常只生成包含7位ASCII字符的输出,以避免传输过程中出现任何潜在的编码问题。
任何JSON解释器都可以使用该字符串并重现原始字符串。 要查看此操作,只需在浏览器的位置栏中输入javascript:alert("ok\u00e9")
即可。
使用Rails2.3.11/Ruby1.8
的其他方法将字符转义为unicode,因此我使用了以下内容:
render :json => JSON::dump(obj)
渲染:如果对象不是字符串,json将在对象上调用.to_json。 您可以通过以下方式避免此问题:
render :json => JSON.generate(obj)
这将直接传递一个字符串,因此避免调用ActiveSupport的to_json。
另一种方法是覆盖您正在序列化的对象上的to_json,因此在这种情况下,您可以执行以下操作:
class Foo < ActiveRecord::Base def to_json(options = {}) JSON.generate(as_json) end end
如果您使用ActiveModelSerializers,您可以通过覆盖序列化程序中的to_json来解决此问题:
# controller respond_with foo, :serializer => MySerializer # serializer attributes :bar, :baz def to_json(options = {}) JSON.generate(serializable_hash) end
我有一个非常棘手的方法来解决这个问题。 好吧,如果to_json
不允许你拥有正确的代码,那么你可以直接尝试写:
render text: tags
render json: tags
或render json: tags.to_json
将始终自动传输编码样式,但如果使用render text:tags
,则字符串将保持原样。 我认为jQuery仍然可以识别数据。