Ответ 1
В Heroku, когда ваше приложение получает сообщение "niño" от Redis, оно фактически получает четыре байта:
0x6e 0x69 0xf1 0x6f
которые, если они интерпретируются как ISO-8859-1, соответствуют символам n
, i
, ñ
и o
.
Однако ваше приложение Rails предполагает, что эти байты следует интерпретировать как UTF-8, и в какой-то момент он пытается их декодировать таким образом. Третий байт в этой последовательности, 0xf1 выглядит следующим образом:
1 1 1 1 0 0 0 1
Если вы сравниваете это с таблицей на странице Википедии, вы можете видеть, что этот байт является ведущим байтом четырехбайтового символа (он соответствует шаблону 11110xxx
), и как таковой должны следовать еще три байта продолжения, которые соответствуют шаблону 10xxxxxx
. Это не так, вместо этого следующий байт равен 0x6f (01101111
), и поэтому это недопустимая последовательность байтов utf-8, и вы получите сообщение об ошибке.
Использование:
string = message.encode('utf-8', 'iso-8859-1')
(или эквивалент Iconv
) сообщает Ruby читать message
как кодировку ISO-8859-1, а затем создать эквивалентную строку в кодировке UTF-8, которую вы можете использовать без проблем. (Альтернативой может быть использование force_encoding
, чтобы сообщить Ruby правильную кодировку строки, но это может вызвать проблемы позже, когда вы пытаетесь смешивать UTF-8 и ISO-8859-1).
В UTF-8 строка "niño" соответствует байтам:
0x6e 0x69 0xc3 0xb1 0x6f
Обратите внимание, что первый, второй и последний байты совпадают. Символ ñ
кодируется как два байта 0xc3 0xb1
. Если вы напишете их в двоичном формате и сравните с таблицей в статье Wikipedia, вы увидите, что они кодируют 0xf1, что является кодировкой ISO-8859-1 ñ
(так как первые 256 кодов Unicode соответствуют ISO-8859- 1).
Если вы берете эти пять байтов и считаете их ISO-8859-1, они соответствуют строке
niño
Глядя на кодировку ISO-8859-1, 0xc3 отображается на Â
, а 0xb1 отображается на ±
.
Итак, что происходит на вашей локальной машине, так это то, что ваше приложение получает пять байтов 0x6e 0x69 0xc3 0xb1 0x6f
от Redis, что является представлением UNF-8 "niño" . На Heroku он получает четыре байта 0x6e 0x69 0xf1 0x6f
, который является представлением ISO-8859-1.
Реальное решение вашей проблемы будет состоять в том, чтобы строки, помещенные в Redis, были уже UTF-8 (или, по крайней мере, все одинаковой кодировкой). Я не использовал Redis, но из того, что я могу сказать из краткого Google, он не относится к строковым кодировкам, а просто возвращает все байты, которые он дал. Вы должны посмотреть, какой процесс помещает данные в Redis, и убедиться, что он правильно обрабатывает кодировку.