Server sent events and browser limits

后端 未结 3 813
被撕碎了的回忆
被撕碎了的回忆 2021-01-30 08:59

I have a web application that listens for Server Sent Events. While I was working and testing with multiple windows open, things were not working and I banged my head for severa

相关标签:
3条回答
  • 2021-01-30 09:36

    The way this works in all browsers are that each domain gets a limited amount of connections and the limits are global for your whole application. That means if you have one connection open for realtime communication you have one less for loading images, css and other pages. On top of that you don't get new connections for new tabs or windows, all of them needs to share the same amount of connections. This is very frustrating but there are good reasons for limiting the connections. A few years back, this limit was 2 in all browsers (based on the rules in (http://www.ietf.org/rfc/rfc2616.txt) HTTP1.1 spec) but now most browsers use 4-10 connections in general. Mobile browsers on the other hand still needs to limit the amount of connections for battery saving purposes.

    These tricks are available:

    1. Use more host names. By assigning ex. www1.domain.com, www2.domain.com you get new connections for each host name. This trick works in all browsers. Don't forget to change the cookie domain to include the whole domain (domain.com, not www.domain.com)
    2. Use web sockets. Web sockets are not limited by these restrictions and more importantly they are not competing with the rest of your websites content.
    3. Reuse the same connection when you open new tabs/windows. If you have gathered all realtime communication logic to an object call Hub you can recall that object on all opened windows like this:

      window.hub = window.opener ? window.opener.hub || new Hub()

    4. or use flash - not quite the best advice these days but it might still be an option if websockets aren't an option.
    5. Remember to add a few seconds of time between each SSE request to let queued requests to be cleared before starting a new one. Also add a little more waiting time for each second the user is inactive, that way you can concentrate your server resources on those users that are active. Also add a random number of delay to avoid the Thundering Herd Problem

    Another thing to remember when using a multithreaded and blocking language such as Java or C# you risk using resources in your long polling request that are needed for the rest of your application. For example in C# each request locks the Session object which means that the whole application is unresponsive during the time a SSE request is active.

    NodeJs is great for these things for many reasons as you have already figured out and if you were using NodeJS you would have used socket.io or engine.io that takes care of all these problems for you by using websockets, flashsockets and XHR-polling and also because it is non blocking and single threaded which means it will consume very little resources on the server when it is waiting for things to send. A C# application consumes one thread per waiting request which takes at least 2MB of memory just for the thread.

    0 讨论(0)
  • 2021-01-30 09:38

    You are right about the number of simultaneous connections.

    You can check this list for max values: http://www.browserscope.org/?category=network

    And unfortunately, I never found any work around, except multiplexing and/or using different hostnames.

    0 讨论(0)
  • 2021-01-30 09:52

    One way to get around this issue is to shut down the connections on all the hidden tabs, and reconnect when the user visits a hidden tab.

    I'm working with an application that uniquely identifies users which allowed me to implement this simple work-around:

    1. When users connect to sse, store their identifier, along with a timestamp of when their tab loaded. If you are not currently identifying users in your app, consider using sessions & cookies.
    2. When a new tab opens and connects to sse, in your server-side code, send a message to all other connections associated with that identifier (that do not have the current timestamp) telling the front-end to close down the EventSource. The front-end handler would look something like this:

      myEventSourceObject.addEventListener('close', () => { myEventSourceObject.close(); myEventSourceObject = null; });

    3. Use the javascript page visibility api to check to see if an old tab is visible again, and re-connect that tab to the sse if it is.

      document.addEventListener('visibilitychange', () => { if (!document.hidden && myEventSourceObject === null) { // reconnect your eventsource here } });

    4. If you set up your server code like step 2 describes, on re-connect, the server-side code will remove all the other connections to the sse. Hence, you can click between your tabs and the EventSource for each tab will only be connected when you are viewing the page.

    Note that the page visibility api isn't available on some legacy browsers: https://caniuse.com/#feat=pagevisibility

    0 讨论(0)
提交回复
热议问题