簡體   English   中英

錯誤地轉義了JSON編碼(Rails 3,Ruby 1.9.2)

[英]JSON encoding wrongly escaped (Rails 3, Ruby 1.9.2)

在我的控制器中,以下工作(打印“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")}

你可以通過猴子修補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。

如果你深入挖掘源代碼,你最終會得到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表示法。 十六進制編碼的UTF-8應該是處理JSON的任何東西都可以接受的,但你總是可以對JSON(或修改后的JSON轉發器中的猴子補丁)進行后處理,以便在必要時將\\uXXXX表示法轉換為原始UTF-8。

我同意強制JSON為7bit-clean有點假,但你去了。

簡答:不。

字符沒有使用Rails2.3.11/Ruby1.8的其他方法轉義為unicode,因此我使用了以下內容:

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

這是正確的編碼。 JSON不requre轉義Unicode字符,但它是常見的JSON庫以產生僅包含7位ASCII字符輸出,以避免在運輸任何潛在的編碼問題。

任何JSON解釋器都可以使用該字符串並重現原始字符串。 要查看此操作,只需在瀏覽器的位置欄中輸入javascript:alert("ok\é")即可。

渲染:如果對象不是字符串,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: tagsrender json: tags.to_json將始終自動傳輸編碼樣式,但如果使用render text:tags ,則字符串將保持原樣。 我認為jQuery仍然可以識別數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM