Вы печатаете Unicode на дескриптор sys.stdout
(который является файловым объектом по умолчанию, print()
записывает в).Затем этот объект должен снова закодировать ваши данные, но он должен делать это в зависимости от среды, к которой он подключен.
Когда вы запускаете python3 ./test.py
, тогда вы подключаетесь к своему терминалу или консоли, и этообычно настраивается на указание сценариям, какой кодек подходит.В системах POSIX (Linux, Mac) вы можете запустить команду locale
, чтобы увидеть, что это за конфигурация.В вашей локали консоли нет проблем с отображением не ASCII-кода, такого как ë
.
Но при запуске в качестве CGI-скрипта, подключенного к веб-серверу, такая языковая конфигурация отсутствует, и Python почти наверняка имеетвместо этого вернулся к наименьшему общему знаменателю: ASCII.И в этом случае попытка распечатать текст не в Юникоде приведет к исключению:
$ LC_ALL="en_US.UTF-8" python3 -c "print(b'Chlo\xc3\xab'.decode())"
Chloë
$ LC_ALL="C" python3 -c "print(b'Chlo\xc3\xab'.decode())" # C => "no locale set"
Traceback (most recent call last):
File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\xeb' in position 4: ordinal not in range(128)
Поскольку исключение имеет место только после создания заголовков и всех других выходных данных,Вы не видите код ошибки HTTP.Однако исключение должно было быть зарегистрировано в журналах ошибок сервера.
Если ваш сценарий должен выводить UTF-8 в браузер, как настроено в заголовке Content-Type, который вы отправляете, replace sys.stdout
для принудительной установки этого кодека:
import sys
from io import TextIOWrapper
sys.stdout = TextIOWrapper(sys.stdout.buffer.detach(), encoding='utf8')
В Python 3 текстовые файлы, подобные тем, которые используются для потока sys.stdout
, содержат объект буфера, который, в свою очередь, содержит объект двоичного файла, который заботитсяфактической записи двоичных данных.Действительно, объект внешнего текстового файла отвечает только за кодирование при записи.Вышеуказанный объект заменяет этот внешний объект другим, который всегда кодируется в UTF-8.