Получение неверного ответа SSE от сервера
Разработка проекта с помощью Django. Установлен DRF. Некоторые процессы в бэкенде генерируют лог-файл. Я ищу в конце файла целевые строки. Когда целевая строка была поймана, она должна быть показана на HTML странице пользователя. Все происходит в динамике.
urls.py
path('api/log-stream/', LogStreamAPIView.as_view(), name='log_stream'),
LogStreamAPIView
class LogStreamAPIView(APIView):
def get(self, request):
def stream_log():
f = subprocess.Popen(['tail', '-F', rcvenot_log], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = select.poll()
p.register(f.stdout)
while TEST_IN_PROGRESS:
if p.poll(0.1):
new_line_log = f.stdout.readline().decode('utf-8').strip()
for target_line in RCV_SCENARIO:
if target_line in new_line_log:
yield f"event: {new_line_log}\n\n"
return StreamingHttpResponse(stream_log(), content_type='text/event-stream')
Сценарий на пользовательской HTML-странице
<div style="width: 200px; height: 200px; overflow-y: scroll;">
<ul id="logList"></ul>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
var logList = document.getElementById('logList');
function updateLog(newLine) {
var listItem = document.createElement('li');
listItem.textContent = newLine;
logList.appendChild(listItem);
}
var source = new EventSource('/api/log-stream/');
source.onmessage = function(event) {
updateLog(event.data);
};
});
</script>
Я вижу строки через API mysite.ru/api/log-stream/
. Некоторые строки
event: 2024.03.22 16:16:13:016[INFO ][Thread-0] ************************* - 2
Но я не вижу их на HTML-странице.
В консоли браузера я вижу код ответа 406: GET 127.0.0.1:8000/api/log-stream 406 (Not Acceptable)
.
В ответе вижу {"detail":"The \"Accept\" request header could not be satisfied."}
Я пробовал бросать данные в разных форматах f"event: {new_line_log}\n\n"
или f"data: {new_line_log}\n\n"
. Это не работает.
Пробовал добавить статус в return StreamingHttpResponse(stream_log(), content_type='text/event-stream’s , status=200)
и status=202
. То же самое
Вот несколько снимков экрана консоли браузера.
Почитайте документацию SSE, сервер должен отвечать Content-Type: text/event-stream
, а в консоли браузера я вижу Content-Type: application/json
. Я подозреваю, что ошибка может быть здесь...
Пожалуйста, помогите разобраться с проблемой
Причина, по которой вы получаете ошибку, заключается в том, что Django Rest Framework пытается выполнить согласование содержимого. По умолчанию он смотрит на параметр DEFAULT_RENDERER_CLASSES
, чтобы определить возможные типы содержимого, которые он может вернуть, и если ничего не подходит, он вернет ошибку 406.
Учитывая, что это ваше конкретное представление, похоже, не использует никакой функциональности, специфичной для DRF, один из вариантов - просто преобразовать его в обычное представление, которое не использует DRF.
Другим решением является создание пользовательского класса согласования контента, который просто игнорирует все согласования контента. Вот пример из документации DRF:
from rest_framework.negotiation import BaseContentNegotiation class IgnoreClientContentNegotiation(BaseContentNegotiation): def select_parser(self, request, parsers): """ Select the first parser in the `.parser_classes` list. """ return parsers[0] def select_renderer(self, request, renderers, format_suffix): """ Select the first renderer in the `.renderer_classes` list. """ return (renderers[0], renderers[0].media_type)
Затем вы измените свое представление, чтобы использовать это для согласования содержимого:
class LogStreamAPIView(APIView):
content_negotiation_class = IgnoreClientContentNegotiation
# Rest of your view
...