Closed enzofrnt closed 6 months ago
On this use case everything is working greate with postman or, Google Chrome but on Angular no… I don't know why
I said in the readme that we need renderer when using Access
in the header. But I'm not sure, maybe that better to use it every time to ensure that we are using the right parameter in the response header.
Can you verify @jkarneges ? Thx.
Thanks, I think it could be good to add such instructions to the readme.
However, I don't understand the part about the renderer. It's just to set response headers? By the way, Access-Control-*
headers should ideally be provided by the django-cors-headers middleware, which hopefully works with DRF too.
Hi @jkarneges, thank you for your answer.
As someone who is relatively new to Django, having recently started using it in my work-study program, I am still on the learning curve. Therefore, some aspects of its implementation are not immediately clear to me, although I understand they serve to resolve specific issues.
In my scenario, the client makes a request and explicitly specifies Accept: text/event-stream
in the request header, indicating a preference
Given that this access parameter seems to be a standard practice for SSE, it's crucial for us to accommodate this requirement.
However, I've encountered a snag. Without adding a specific renderer to the view, the response defaults to Content-Type: application/json
. This contrasts with our client's explicit requirement for Content-Type: text/event-stream
. I'm keen to understand the necessity of adjusting the Content-Type
to adhere to the SSE standard and ensure compatibility with the client's expectations.
Because if we don't adhere, we get an error like this one :
If my understanding is correct, we need to add a renderer to modify the response header by including all necessary elements for a functional SSE response.
How, and if in the same time we can carefully make the module compatible as possible with this module drf-spectacular that will be pretty nice for documented use cases.
Here is the last version of my code for those supports :
class TextEventStreamRenderer(BaseRenderer):
"""
A renderer to stream events to the client in text/event-stream format and add the right CORS headers.
"""
media_type = 'text/event-stream'
charset = 'utf-8'
format = 'event-stream'
Access_Control_Allow_Origin = EVENTSTREAM_ALLOW_ORIGIN
def render(self, data, accepted_media_type=None, renderer_context=None):
# Ensure data is a byte string
if isinstance(data, str):
data = data.encode(self.charset)
return data
class EventsViewSet(ViewSet):
"""
A viewset to stream events to the client.
"""
renderer_classes = [TextEventStreamRenderer]
def list(self, request, *args, **kwargs):
channels = ['parser', 'scanner']
kwargs['channels'] = channels
django_request = request._request if hasattr(request, '_request') else request
return events(django_request, **kwargs)
@jkarneges I'm working on something better 👀
@jkarneges Here is what I have done.
Extend HTML to display the ongoing event.
{% extends "rest_framework/base.html" %}
{% block script %}
<script type="text/javascript">
var currentPageUrl = window.location.href;
// Exemple d'utilisation : affichage dans la console
console.log("URL actuelle :", currentPageUrl);
var eventsContainer = document.querySelectorAll('.meta');
console.log("Conteneur d'événements :", eventsContainer);
eventsContainer[0].innerHTML += "<div id=\"sse-events\">Événements SSE s'afficheront ici...</div>"
var eventSource = new EventSource(currentPageUrl);
eventSource.onmessage = function(event) {
console.log("Nouvel événement SSE :", event.data);
eventsContainer[0].innerHTML += "<p>" + event.data + "</p>";
};
</script>
{{ block.super }}
{% endblock %}
Renderer for SSE (Django did not have one working for SSE) :
from rest_framework.renderers import BaseRenderer
from project.settings import EVENTSTREAM_ALLOW_ORIGIN
class SSEEventRenderer(BaseRenderer):
"""
A renderer to stream events to the client in text/event-stream format and add the right CORS headers.
"""
media_type = 'text/event-stream'
Access_Control_Allow_Origin = EVENTSTREAM_ALLOW_ORIGIN
def render(self, data, accepted_media_type=None, renderer_context=None):
# Ensure data is a byte string
if isinstance(data, str):
data = data.encode(self.charset)
return data
A view set that I have tried to do… If you have competence to work on it, please take a look at it.
class EventsViewSet(ViewSet):
"""
A viewset to stream events to the client.
"""
http_method_names = ['get']
def list(self, request, *args, **kwargs):
channels = ['parser', 'scanner']
kwargs['channels'] = channels
django_request = request._request if hasattr(request, '_request') else request
# Vérifie si le type de contenu accepté est "text/event-stream"
if django_request.META.get('HTTP_ACCEPT') :
print(django_request.META.get('HTTP_ACCEPT'))
if 'text/event-stream' in django_request.META.get('HTTP_ACCEPT') :
return events(django_request, **kwargs)
elif 'text/html' in django_request.META.get('HTTP_ACCEPT'):
return render(django_request, 'events.html', context={'channels': channels})
return Response({'error': 'Bad request'}, status=400)
I just add the renderer because for me, it didn't need more. Please let me know what you think, and may be help me
Related to #138, I updated to specify how to use it with Django-restframework and also a little adjustment about using something as Redis when using different process…