【问题标题】:JSON encoding wrongly escaped (Rails 3, Ruby 1.9.2)JSON 编码错误转义(Rails 3、Ruby 1.9.2)
【发布时间】:2011-07-04 16:26:12
【问题描述】:

在我的控制器中,以下工作(打印“oké”)

puts obj.inspect

但这不会(呈现“ok\u00e9”)

render :json => obj

显然to_json 方法转义了 unicode 字符。有没有办法防止这种情况发生?

【问题讨论】:

    标签: ruby-on-rails ruby json encoding


    【解决方案1】:

    将 \uXXXX 代码设置回 utf-8:

    json_string.gsub!(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
    

    【讨论】:

      【解决方案2】:

      你可以通过猴子补丁来防止它 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 中的表情符号问题。谢谢!
      • 在 Rails 3.1.6 中仍然是一个问题,这个补丁仍然修复了它。 Rails 团队确实需要在他们的 JSON 编码中解决这个问题;表情符号不会消失,尤其是现在它已成为 Unicode 标准的一部分。
      • 看到这个不那么可怕的解决方案:stackoverflow.com/questions/683989/…
      【解决方案3】:

      如果你挖掘源代码,你最终会找到ActiveSupport::JSON::Encodingescape 方法:

      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 表示法。处理 JSON 的任何东西都应该接受十六进制编码的 UTF-8,但您始终可以对 JSON(或修改后的 JSON 转义器中的猴子补丁)进行后处理,以在必要时将 \uXXXX 表示法转换为原始 UTF-8。

      我同意强制 JSON 为 7bit-clean 有点假,但你去吧。

      简短回答:不。

      【讨论】:

        【解决方案4】:

        Rails2.3.11/Ruby1.8 中的其他方法没有将字符转义为 unicode,因此我使用了以下方法:

        render :json => JSON::dump(obj)
        

        【讨论】:

        • 这在 Rails 4.2.5 / Ruby 2.2.3 中仍然适用于我
        • 效果很好。谢谢!
        【解决方案5】:

        这是正确的编码。 JSON要求转义 Unicode 字符,但 JSON 库通常会生成仅包含 7 位 ASCII 字符的输出,以避免在传输过程中出现任何潜在的编码问题。

        任何 JSON 解释器都可以使用该字符串并重现原始字符串。要查看实际情况,只需在浏览器的地址栏中输入 javascript:alert("ok\u00e9")

        【讨论】:

          【解决方案6】:

          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
          

          【讨论】:

            【解决方案7】:

            我有一个非常棘手的方法来解决这个问题。好吧,如果to_json不允许你有正确的代码,那你可以直接尝试写:

            render text: tags
            

            render json: tagsrender json: tags.to_json 将始终自动转换编码样式,但如果您使用render text:tags,则字符串将保持原样。而且我认为 jQuery 仍然可以识别数据。

            【讨论】:

              猜你喜欢
              • 2011-06-13
              • 1970-01-01
              • 2011-07-03
              • 1970-01-01
              • 1970-01-01
              • 2011-11-01
              • 1970-01-01
              • 1970-01-01
              • 2011-06-09
              相关资源
              最近更新 更多