В Respons-е Starlette (FastAPI) пытаюсь передать кириллический текст, получаю UnicodeEncodeError: 'latin-1' codec can't encode characters
from fastapi import Response
@app.get(f'/customCyrillicHeader')
def test(resp: Response):
resp.headers['X-API-Code'] = "Это киррилица, бро"
return 'ok'
Получаю такой стэк:
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 369, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 59, in __call__
return await self.app(scope, receive, send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\fastapi\applications.py", line 208, in __call__
await super().__call__(scope, receive, send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
raise exc from None
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\exceptions.py", line 82, in __call__
raise exc from None
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\routing.py", line 580, in __call__
await route.handle(scope, receive, send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\routing.py", line 241, in handle
await self.app(scope, receive, send)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\routing.py", line 52, in app
response = await func(request)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\fastapi\routing.py", line 220, in app
dependant=dependant, values=values, is_coroutine=is_coroutine
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\fastapi\routing.py", line 154, in run_endpoint_function
return await run_in_threadpool(dependant.call, **values)
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\concurrency.py", line 40, in run_in_threadpool
return await loop.run_in_executor(None, func, *args)
File "C:\Python37\lib\concurrent\futures\thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "D:\Projects\RecalcAPIfast\app\main.py", line 18, in test
resp.headers['X-API-Code'] = "Это киррилица, бро"
File "D:\Projects\RecalcAPIfast\venv\lib\site-packages\starlette\datastructures.py", line 585, in __setitem__
set_value = value.encode("latin-1")
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-2: ordinal not in range(256)
В starlette\datastructures.py явное кодирование в latin-1
class MutableHeaders(Headers):
def __setitem__(self, key: str, value: str) -> None:
"""
Set the header `key` to `value`, removing any duplicate entries.
Retains insertion order.
"""
set_key = key.lower().encode("latin-1")
set_value = value.encode("latin-1")
found_indexes = []
for idx, (item_key, item_value) in enumerate(self._list):
if item_key == set_key:
found_indexes.append(idx)
for idx in reversed(found_indexes[1:]):
del self._list[idx]
if found_indexes:
idx = found_indexes[0]
self._list[idx] = (set_key, set_value)
else:
self._list.append((set_key, set_value))
Но насколько мне известно, header можно передавать объектом в base64. Но я не пойму как это сделать в FastAPI. Например Django rest framework сам кодирует в base64 и передает, ничего придумывать не нужно. Помогите плизз!
Ответы (1 шт):
Автор решения: insolor
→ Ссылка
Можно вручную закодировать строку в байты с помощью кодировки utf-8, потом перекодировать в base64, и потом уже присвоить в resp.headers['X-API-Code']:
from base64 import b64encode
from fastapi import FastAPI, Response
app = FastAPI()
@app.get(f'/customCyrillicHeader')
def test(resp: Response):
resp.headers['X-API-Code'] = b64encode("Это киррилица, бро".encode('utf-8')).decode()
return 'ok'
Вызов decode в конце нужен, чтобы превратить набор байт, который вернула функция b64encode, обратно в строку (без этого будет вылетать ошибка, что у байт нет метода encode).