How to turn off buffering on Nginx Server for Server sent event
Asked Answered
L

2

9

Problem : Nginx Server is buffring the Server sent events(SSE).

Setup : Node v12.13.1, Nginx 1.16.1, Chrome v80

Scenario: I tried to turn off buffering with proxy_buffering off; and even added "X-Accel-Buffering": "no" in server resonse header however nginx is still buffering all SSE. if I close node server or restart nginx server then all the SSE message are delivered to client in bulk. I tried alot but dont know that I'm missing.

Nginx Config file :


events {
    worker_connections  1024;
}

http {
    include       mime.types;
    sendfile        on;   
    keepalive_timeout  65;

    server {
        listen       4200;
        server_name  localhost;

        location / {    
            proxy_set_header Connection '';
            proxy_http_version 1.1;
            chunked_transfer_encoding off;
            proxy_buffering off;
            proxy_cache off;
            proxy_pass http://localhost:8700;
        }
    }
}

Node Server :

var express = require('express');
var app = express();

var template = 
`<!DOCTYPE html> <html> <body>
    <script type="text/javascript">
        var source = new EventSource("/events/");
        source.onmessage = function(e) {
            document.body.innerHTML += e.data + "<br>";
        };
    </script>
</body> </html>`;

app.get('/', function (req, res) {
    res.send(template); // <- Return the static template above
});

var clientId = 0;
var clients = {}; // <- Keep a map of attached clients

// Called once for each new client. Note, this response is left open!
app.get('/events/', function (req, res) {
    req.socket.setTimeout(Number.MAX_VALUE);
    res.writeHead(200, {
        'Content-Type': 'text/event-stream', // <- Important headers
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'X-Accel-Buffering': 'no'
    });
    res.write('\n');
    (function (clientId) {
        clients[clientId] = res; // <- Add this client to those we consider "attached"
        req.on("close", function () {
            delete clients[clientId]
        }); // <- Remove this client when he disconnects
    })(++clientId)
});

setInterval(function () {
    var msg = Math.random();
    console.log("Clients: " + Object.keys(clients) + " <- " + msg);
    for (clientId in clients) {
        clients[clientId].write("data: " + msg + "\n\n"); // <- Push a message to a single attached client
    };
}, 2000);

app.listen(process.env.PORT || 8700);
Lynch answered 4/4, 2020 at 13:48 Comment(3)
see also #13673243Manned
I added proxy_buffering off; directly inside the http section which was all that was necessary to get it to work for a Flask app. I don't know anything about Nginx so maybe this is already implied by your config.Palladium
I have the same exact issue. Were you able to solve it?Scrawl
G
3

In my case (I had the same issue) it was nginx in front of nginx: even if you set x-accel-buffering: no, the internal nginx "eats" it and the external nginx buffers the response. If this is the case, you can pass the header via:

proxy_pass_header X-Accel-Buffering;
Godin answered 5/12, 2023 at 10:39 Comment(0)
R
0

There were many good answers to this question, but unfortunately a lot of them would result in normal requests being unbuffered. To avoid this, I opted to create an isolated path. I created a subdomain "event.mydomain" and pointed that to the same port as my normal "api.mydomain". In the nginx config for that route I turned off buffering and caching. I also turned off connection upgrades, but I don't believe that had an effect, but it was recommended so for now it's off.

server {
        server_name events.mydomain.com www.events.mydomain.com;
        access_log /var/log/nginx/events.mydomain.com.access.log;
        error_log /var/log/nginx/events.mydomain.com.error_log;

        underscores_in_headers on;

        location / {
                proxy_pass http://localhost:30010;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Connection "";
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
                proxy_pass_request_headers on;
                proxy_buffering off;
                proxy_cache off;
        }
       
}

And in my application code I made sure to also set the connection to keep-alive, text/event-stream, no-cache, and the import one for this issue, "X-Accel-Buffering": "no"

conn.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Connection': 'keep-alive',
      'Cache-Control': 'no-cache',
      'X-Accel-Buffering': 'no'
    })

This way I have a dedicated event pipe that is unbuffered, and it seems to be holding up well. Hope this tip helps anyone in the future.

Rufe answered 2/8, 2024 at 6:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.