Я разворачиваю интерфейс Rails, который разговаривает с API-интерфейсом Grape. Это второй экземпляр этой программы. Первый экземпляр работает хорошо. Однако API-интерфейс Grape второго экземпляра, похоже, искажает данные перед отправкой по каналу.Почему преобразование кодировки Ruby Base64 потеряло данные и как я могу маршрутизировать?
Мне нужно изображение, чтобы перейти от файла> json> http> db. Прямо сейчас я делаю это, отправляя файл следующим образом: file> string> encode to url-safe base64> to_json> http> decode> save to sqlite3 db с ActiveRecord. Я убежден, что данные изображения повреждены, и я перевел его на base64 на основе ниже. Однако, поскольку Grape - это все JSON, символы должны быть закодированы перед отправкой (поскольку, по крайней мере, насколько это касается библиотеки JSON Ruby, недопустимый UTF-8 == недействительный JSON).
Так что я либо должен знать:
- Как разрешить Grape API для отправки не-JSON (сырой строки файла) или
- Как декодировать строку и избежать появления сообщения об ошибке
Открытие файла и преобразование его содержимого в безопасное для ссылок Base64.
File.open("#{folder}/#{file_name}", "rb:UTF-8") do |image|
file_as_string = image.read
end
=> "iVBORw0K ... # truncated for length
Вещи сразу исчезают. IRB делает ожидаемый - кодируется как UTF-8.
file_as_string.encoding.name
=> "UTF-8"
НО. Журналы сервера ASCII-8BIT
. Я не могу это объяснить. Каждый файл увенчан магическим комментарием Ruby's UTF-8. Linux $LANG
установлен в en_US.UTF-8
.
OK, но когда Base64 конвертирует, я все равно теряю сюжет. Даже в IRB, начиная с UTF-8, он скрывается. Почему US-ASCII? Независимо от того, почему совместимость теряется ?.
Base64.urlsafe_encode64(file_as_string).encoding.name
=> "US-ASCII"
Base64.urlsafe_decode64(Base64.urlsafe_encode64(file_as_string)).encoding.name
=> "ASCII-8BIT"
Base64.urlsafe_decode64(Base64.urlsafe_encode64(file_as_string)).encode("UTF-8")
Encoding::UndefinedConversionError: "\x89" from ASCII-8BIT to UTF-8
from (irb):27:in `encode'
from (irb):27
from /home/me/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'
Обратите внимание, что здесь ошибка в IRB то же самое, как если бы я а) не base64 закодировать строку перед тем винограда пытается to_json и б) когда я пытаюсь расшифровать и позвонить .save
строка для атрибута модели на стороне Rails.
Сам файл является двоичным (если это имеет значение?)
$ file -bi /path/to/file.png
image/png; charset=binary
Solutions Я пытался, или я не желает попробовать:
Отправка по сырым image.read
Это JSON API, поэтому Grape конвертирует в JSON перед отправкой данных по проводу - это означает, что любой ответ должен быть действительным JSON, насколько я знаю выдержать это. Если я попытаюсь отправить необработанную строку, автоматически вызванная .to_json
выдает ту же ошибку.
Force-кодирующих результаты
Выходной сигнал не является читаемой PNG.
Downgrading
оригинальный экземпляр Руби 1.9.2 и CentOS 6.3. Новый экземпляр Ruby 2.2.1 и CentOS 7. Я, как правило, готов двигаться вперед, поэтому я предпочел бы разработать какое-то решение, даже если оно не совместимо с обратной совместимостью, а затем откат Ruby и моей ОС.
Не используя UTF-8
Rails config/application.rb
имеет игровую линию config.encoding = "utf-8"
и config/environment.rb
имеют линию Encoding.default_external = Encoding::UTF_8; Encoding.default_internal = Encoding::UTF_8
, я надеюсь, не придется отказываться от совместимости UTF-8 только для этого одного вопроса.
Так есть ли способ, чтобы служить файл непосредственно в винограде, минуя to_json
вызов? Или существует другой безопасный кодировщик для JSON-ing и отправки по http?
Вы правы, но, к сожалению, конечный результат, который мне нужен, это сохранение строки в столбце базы данных SQLite 3. (Я пытался прояснить это.) Я вызываю '.encode()' в моем воспроизведении IRB, потому что Rails вызывает '.encode()' перед тем, как он сохранит строку в базе данных. IRB просто демонстрирует, что строка не может быть закодирована в UTF-8 и полученная ошибка. – Sam
@ Да. Будьте осторожны, чтобы не изменить сферу действия вопроса, чтобы включить Rails. Перед тем, как обратить внимание на Rails, запустите часть Grape. Ваш IRB не представляет, что происходит за кулисами, поскольку Grape не должен вызывать '.encode()' в декодированной строке. Не изменяйте .png на диске и не устанавливайте кодировку. Просто передайте строку base64 в Grape. Подтвердите, что это работает с 'curl' и вручную base64 декодирует результат обратно на изображение. Только тогда вы должны начать играть с Rails.После того, как у вас есть строка base64 в Rails, вы должны сохранить в db –
Извините - не пытайтесь изменить область действия. IRB был просто попытался поставить диагноз проблемы. Мой вопрос был и до сих пор связан с кодировками, которые я не понимаю, как строка UTF-8 может иметь недопустимые символы UTF-8, просто запускаясь через '.encode64', а затем через' .decode64'. Я бы хотел, чтобы это ответили. Тем не менее, в основном мне хотелось бы, чтобы он ответил, чтобы приложение API и Rails играло хорошо. – Sam