Кодировка JSON неверно экранирована (Rails 3, Ruby 1.9.2) - PullRequest
19 голосов
/ 26 февраля 2011

В моем контроллере работает следующее (печатает "oké")

puts obj.inspect

Но это не так (отображает "ok \ u00e9")

render :json => obj

Видимо, метод to_json экранирует символы Юникода. Есть ли возможность предотвратить это?

Ответы [ 7 ]

34 голосов
/ 19 июля 2011

Чтобы установить коды \ uXXXX обратно в utf-8:

json_string.gsub!(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
21 голосов
/ 01 декабря 2011

Вы можете предотвратить это, исправляя обезьяны, метод, упомянутый muu, слишком короткий. Поместите следующее в config / initializer / 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.

15 голосов
/ 26 февраля 2011

Если вы покопаетесь в источнике, вы в конечном итоге получите 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 бит немного обманчиво, но все готово.

Краткий ответ: нет.

12 голосов
/ 19 февраля 2013

Символы не были переведены в юникод с другими методами в Rails2.3.11/Ruby1.8, поэтому я использовал следующее:

render :json => JSON::dump(obj)
9 голосов
/ 26 февраля 2011

Это правильная кодировка.JSON не требует символов Unicode, которые необходимо экранировать, но для библиотек JSON свойственно выводить данные, содержащие только 7-битные символы ASCII, чтобы избежать любых потенциальных проблем кодирования при передаче.* Любой интерпретатор JSON сможет использовать эту строку и воспроизвести оригинал.Чтобы увидеть это в действии, просто введите javascript:alert("ok\u00e9") в адресную строку браузера.

2 голосов
/ 26 января 2016

render: json вызовет .to_json для объекта, если это не строка. Вы можете избежать этой проблемы, выполнив:

render :json => JSON.generate(obj)

Это будет напрямую передавать строку и, следовательно, избегать вызова to_json ActiveSupport.

Другой подход заключается в переопределении to_json для объекта, который вы сериализуете, поэтому в этом случае вы можете сделать что-то вроде:

class Foo < ActiveRecord::Base
  def to_json(options = {})
    JSON.generate(as_json)
  end
end

И если вы используете ActiveModelSerializer, вы можете решить эту проблему, переопределив to_json в вашем сериализаторе:

# controller
respond_with foo, :serializer => MySerializer

# serializer
attributes :bar, :baz

def to_json(options = {})
  JSON.generate(serializable_hash)
end
0 голосов
/ 24 марта 2012

У меня есть очень хитрый способ решить эту проблему.Хорошо, если to_json не позволил вам иметь правильный код, то вы можете напрямую попытаться написать:

render text: tags

render json: tags или render json: tags.to_json всегда будет автоматически передавать стиль кодирования, но есливы используете render text:tags, тогда строка останется как есть.И я думаю, что jQuery все еще может распознавать данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...