16

I implement some code to query the database for any changes and to send an event. Here's the code of my PHP script

header("Content-Type: text/event-stream");
header('Cache-Control: no-cache');

//****Some code here to query the database

echo "event: message\n";
echo "data: change_from_database \n";
echo "\n\n";
ob_flush();
flush();

I'm relying on the browser to automatically reconnect each time the connection closes, so I don't implement any loop on my server code. In addition, I learned from this thread that implementing an infinite loop has many disadvantages.

So everything works fine client-side: the browser reconnects each time the connection closes and an event is fired each time the server sends one; well except for Firefox (40.0.2) which doesn't reconnect. I know it doesn't because I wrote some JavaScript error checking code to test this:

var evtSource = new EventSource("../sse.php");
evtSource.onerror = function(event){
    var txt;
    switch( event.target.readyState ){
    case EventSource.CONNECTING:
        txt = 'Reconnecting...';
        break;
    }
    console.log(txt);
}

So after like each second, the console on chrome for example logs "Reconnecting". Firefox on the other hand reconnects once and never does so again.

How do I write code to make this work on Firefox, and perhaps other browsers which support server-sent events but don't reconnect automatically?

Community
  • 1
  • 1
Cedric Ipkiss
  • 5,662
  • 2
  • 43
  • 72
  • 2
    http://stackoverflow.com/questions/11077857/what-are-long-polling-websockets-server-sent-events-sse-and-comet – Matt Feb 21 '16 at 16:03
  • Thanks, @mkaatman, but that thread explains what technologies like SSE do. I know a little of what each of these technologies do, and that's why I'm having problems with one of them – Cedric Ipkiss Feb 21 '16 at 17:04
  • Any chance you can switch to web sockets? – Matt Feb 21 '16 at 17:09
  • I learned websockets are easier and best with node.js. Problem is with none of my web projects running on dedicated servers, I've run into difficulties using node.js. But it's something I'm willing and ready to dedicate all my time on, if it's a good technology. – Cedric Ipkiss Feb 21 '16 at 17:14
  • Can you test your code with `header('Transfer-Encoding: identity');` ? I don't know will it helps or not, just suggestion. – Wizard Feb 25 '16 at 02:44
  • Is there any error message in the developer console? – max Feb 27 '16 at 05:31

3 Answers3

6

With the recent version of the Firefox browser (44.0.2), your code works perfectly. However, you can reinitialize your EventSource object in the error handler like this:

var evtSource = new EventSource("../sse.php");
var evtSourceErrorHandler = function(event){
    var txt;
    switch( event.target.readyState ){
        case EventSource.CONNECTING:
            txt = 'Reconnecting...';
            break;
        case EventSource.CLOSED:
            txt = 'Reinitializing...';
            evtSource = new EventSource("../sse.php");
            evtSource.onerror = evtSourceErrorHandler;
            break;
    }
    console.log(txt);
}

But I strongly do not recommend you to do this because your code doesn't use benefits of keeping the connection alive (as you wrote, you are aware of infinite loop) so browser does simple polling (you can see this in then network tab). I don't see any reason to use SSE over AJAX without keeping a permanent connection, which is obviously hard to maintain with PHP. So I assume using simple AJAX polling in this situation.

max
  • 2,757
  • 22
  • 19
  • Thanks, @max; I didn't go for AJAX polling because of the overhead of transferring data between client and server through new headers for each connection. Also, I just ran the code on version 44.0.2 and it reconnects just once – Cedric Ipkiss Feb 27 '16 at 15:13
  • 1
    Unfortunately, your assumption about avoiding of transferring data overhead is false as reconnecting the server using SSE sends as much headers information as simple AJAX call. You can check it by yourself in the `Network` tab of a browser. – max Feb 27 '16 at 15:48
  • i really don't think it does, @max...http://stackoverflow.com/questions/9397528/server-sent-events-vs-polling – Cedric Ipkiss Feb 27 '16 at 18:53
  • 1
    @che-azeh That's true until the script reconnects each request and use a 'single long-lived HTTP connection.' Each time your script reconnecting, it sends headers as AJAX polling and you can easily verify it as I did using Developers Tools of a browser. – max Feb 27 '16 at 20:34
  • 1
    Thanks for the clarification, @max. totally understood! :). I'm awarding the bounty mainly because your answer was the only one which in addition to solving my problem, helped me improve my knowledge of SSE – Cedric Ipkiss Feb 27 '16 at 23:19
  • "But I strongly do not recommend you to do this because your code doesn't use benefits of keeping the connection alive" I don't understand. It looks like your code will work fine by "ignoring" the first Firefox retry connection and then reestablishing a new EventSource on the 2nd failure. What is the down side to this? This looks like it would behave exactly the way Chrome does natively. Could you help me understand the concern? – Josh Johnson Mar 05 '17 at 00:20
  • Actually, on the Firefox version mentioned (and perhaps other recent versions), it does not reestablish the connection on the second failure. That's where it's different from chrome; you can't rely on it to reconnect automatically. Also, we can't keep the connection open from PHP by `sleeping` the server, as my question says. – Cedric Ipkiss Mar 05 '17 at 09:27
3

You could use a polyfill like this one https://github.com/Yaffle/EventSource which should add the event source functionality to unsupported browsers.

user874639
  • 153
  • 1
  • 8
1

Ran a test with your code on my site and everything works as expected with Firefox 44.0.2 and php 5.5. I did run into something interesting on the Mozilla dev network though that states you can't necessarily tell what the error message was on Firefox past v22. Perhaps your switch statement in the error checking that is what's letting you down. Here's a link to the article. Check out the error handling section.

My php code is identical to yours. Just in case I did something different, here's my html code.

<!DOCTYPE>
<html>
<head>
    <title>SSE Test</title>
    <meta charset="utf-8" />
    <script>
      var evtSource = new EventSource("sse.php");
      evtSource.onerror = function(event){
        var txt;
        switch( event.target.readyState ){
           case EventSource.CONNECTING:
               txt = 'Reconnecting...';
               break;
        }
        console.log(txt);
      };
    </script>
  </head>
  <body></body>
</html>
OffTheBricks
  • 425
  • 2
  • 9
  • Thanks, @OffTheBricks; don't know if I'm missing something but my Firefox is updated and when I run the code, it reconnects once and after that, never does again. Issue was that it has to reconnect always, like it does on Chrome. So every time it reconnects, it checks if any updates are available. – Cedric Ipkiss Feb 27 '16 at 15:16