在我的控制器中,可以执行以下操作(打印“oké”)
puts obj.inspect
但这不是(呈现“ok\u00e9”)
render :json => obj
显然
to_json
方法转义了 unicode 字符。有办法阻止这种情况吗?
将 \uXXXX 代码设置回 utf-8:
json_string.gsub!(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
你可以通过猴子补丁来防止它,mu提到的方法太短了。将以下内容放入 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。
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
表示法。十六进制编码的 UTF-8 应该可以接受任何处理 JSON 的东西,但如果需要,您始终可以对 JSON(或修改后的 JSON 转义器中的猴子补丁)进行后处理,以将 \uXXXX
表示法转换为原始 UTF-8。
我同意强制 JSON 为 7 位干净有点假,但你就知道了。
简短回答:不。
Rails2.3.11/Ruby1.8
中的其他方法没有将字符转义为unicode,所以我使用了以下方法:
render :json => JSON::dump(obj)
这是正确的编码。 JSON 不要求转义 Unicode 字符,但 JSON 库通常会生成仅包含 7 位 ASCII 字符的输出,以避免传输过程中出现任何潜在的编码问题。
任何 JSON 解释器都能够使用该字符串并重现原始字符串。要查看实际效果,只需在浏览器的地址栏中输入
javascript:alert("ok\u00e9")
。
render :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 仍然可以识别数据。