SSE using NGINX + PHP returns in large chunks with headers missing

52 views Asked by At

I am using SSE EventStream to stream large text to the client. My local Apache+PHP works great, however our NGINX+PHP servers are behaving oddly: There is an initial delay that is always ~10x of the word delay added below, and the stream comes in larger chunks rather than word-by-word, as expected. Also, the Transfer-encoding: chunked and X-Accel-Buffering: no are missing in response headers.

PHP code:

public function sse($delay = 50)
    {
        // Sample paragraph of text
        $paragraph = "This is a sample paragraph of text. This is a sample paragraph of text. This is a sample paragraph of text. This is a sample paragraph of text. This is a sample paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec elit sit amet a. This is a sample paragraph of text. This is a sample paragraph of text. This is a sample paragraph of text. This is a sample paragraph of text. This is a sample paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec elit sit amet a";

        // Split the paragraph into an array of words
        $words = explode(' ', $paragraph);

        // Set up headers for streaming
        header('X-Accel-Buffering: no');
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache');
        header('Connection: keep-alive');

        ini_set('zlib.output_compression', 0);
        ini_set('implicit_flush', 1);
        // This function discards the contents of the topmost output buffer and turns off this output buffering.
        @ob_end_clean();


        for ($i = 0; $i < ob_get_level(); $i++) { //for each open buffer
            @ob_end_flush(); //close it
        }

        @ob_implicit_flush(1); //turn implicit flush on 

        // Emit "word" event for each word
        $id = 1;
        foreach ($words as $word) {
          echo "id: $id".PHP_EOL;
            echo "event: word".PHP_EOL;
            echo "data: $word".PHP_EOL;
            echo PHP_EOL;
            @ob_flush();
            flush();
            usleep($delay*1000); // Delay between each word (in microseconds)
            $id++;
        }
        @ob_flush();
        flush();
    }

Response Headers (missing Transfer-encoding: chunked and X-Accel-Buffering: no)

Cache-Control: no-cache;
Pragma: no-cache;
Content-Type: text/event-stream;charset=UTF-8;
...

Tried all the recommended settings below (together and separately).

NGINX Config

proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding on;
proxy_buffering off;
proxy_cache off;
fastcgi_buffering off;

Only proxy_http_version seemed to make a difference. When not set, the whole result is returned at once. When set, there is streaming but with the aforementioned delay and larger chunks.

0

There are 0 answers