Server Sent Event (SSE) para hacer tiempo real en javascript

 Una de las formas para hacer tiempo real en la web es utilizando la API de SSE(Server Sent Event) que es unidireccional quiere decir que el servidor es el único que notifica, cosa contraria respecto a los web sockets que son bidireccional.

Ejemplo.

1. Archivo Html


<!DOCTYPE html>

<html>

<head>

    <meta name="viewport" content="width=device-width" />

    <title>Index</title>

    <style>

        html, body {

            padding: 0px;

            margin: 0px;

            font-family: sans-serif;

        }

        .titulo {

            padding: 15px;

            font-weight: bold;

            background-color: #073f67;

            text-align: center;

            color: #fff;

        }

        .fila {

            display: flex;

            flex-direction: row;

            justify-content: center;

            align-items: center;

            column-gap: 15px;

            margin: 10px 0px;

        }

       .boton {

            background-color: #137fb3;

            color: white;

            border: none;

            border-radius: 6px;

            padding: 10px 15px;

            cursor: pointer

        }

            .boton:hover {

                opacity: 0.9;

                box-shadow: 1px 1px 1px 0px #b9b2b2, 2px 2px 2px 0px #b1acac;

            }

        /*tabla*/

        table {

            font-family: arial, sans-serif;

            border-collapse: collapse;

            width: 100%;

        }

        td, th {

            border: 1px solid #dddddd;

            text-align: left;

            padding: 8px;

        }

        tr:nth-child(even) {

            background-color: #dddddd;

        }

    </style>

</head>

<body>

    <div class="titulo">Server Sent Events</div>

    <div class="fila">

        Usuario <input type="text" id="txtUsuario"/> <button id="btnsuscribirse" class="boton">Suscribirse</button>

    </div>

    <div class="fila"> 

        Mensaje <input type="text" id="txtMensaje" /> <button id="btnEnviar" class="boton" style="width:100px">Enviar</button>

    </div>

    <div class="fila">

        <table>

            <thead>

                <tr>

                    <th>Mensajes</th>

                </tr>

            </thead>

            <tbody id="tbMensajes"></tbody>

        </table>

    </div>

    <script src="~/Scripts/ServerSentEvent.js"></script>

</body>

</html>

2. Archivo Javascript

let sse;
window.onload = function () {

    let btnsuscribirse = document.getElementById("btnsuscribirse");
    btnsuscribirse.onclick = function () {

        suscribir();
    }

    let btnEnviar = document.getElementById("btnEnviar");
    btnEnviar.onclick = function () {
        let txtMensaje = document.getElementById("txtMensaje").value;

        servidor({ metodo: "post", url: "/ServerSentEvent/notificar", data: txtMensaje }).then((data) => {

            console.log(data);
        })
    }

}

function suscribir() {

    let txtUsuario = document.getElementById("txtUsuario").value;

    sse = new EventSource("/ServerSentEvent/suscribirse?usuario=" + txtUsuario);

    sse.onopen = function () {
        console.log("conectado");
    }

    sse.addEventListener("notificar", function (e) {

        let mensaje = e.data;
        let html = "<tr><td>" + mensaje + "</td></tr>";
        document.getElementById("tbMensajes").insertAdjacentHTML("beforeend", html);

    })

}


function servidor({ metodo = "get", url = null, data = null, responsetype = "text" } = {}) {

    return new Promise((resolve, reject) => {

        let xhr = new XMLHttpRequest();
        xhr.open(metodo, url);

        xhr.responseType = responsetype;

        xhr.onreadystatechange = function () {

            if (xhr.readyState == 4 && xhr.status == 200) {

                resolve(xhr.response);
            }
        }
        xhr.onerror = function (e) {

            reject(e)
        }

        let fd = null;
        if (data) {
            fd = new FormData();
            fd.append("data", data);
        }


        xhr.send(fd);

    });

}

3.  controlador C#:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using System.Web;

using System.Web.Mvc;

namespace PracticaJavascriptAPI.Controllers

{

    public class ServerSentEventController : Controller

    {

        public static ConcurrentQueue<string> lstMensajes = new ConcurrentQueue<string>();

        public static Dictionary<string, HttpResponseBase> lstUsuarios = new Dictionary<string, HttpResponseBase>();


        public ActionResult Index()

        {

            return View();

        }

       public async Task suscribirse() {

            string usuario = Request.QueryString["usuario"];

            Response.Clear();

            Response.ContentType = "text/event-stream";

            Response.CacheControl = "no-cache";

            if (!lstUsuarios.ContainsKey(usuario))

            {

                lstUsuarios.Add(usuario, Response);

            }

            else {

                lstUsuarios[usuario] = Response;

            }

            string mensaje = "";

            do

            {

                if (lstMensajes.Count > 0)

                {

                    if (lstMensajes.TryDequeue(out mensaje)) {

                        for (int i = 0; i < lstUsuarios.Count; i++)

                        {

                            lstUsuarios.ElementAt(i).Value.Write("id:" + DateTime.Now.ToString("HHmmss") + "\n");

                            lstUsuarios.ElementAt(i).Value.Write(mensaje);

                            lstUsuarios.ElementAt(i).Value.Flush();

                        }

                    }

                }

                else {

                    Response.Flush();

                }

               await Task.Delay(50);

            } while (true);

        }


        public string notificar(string data) {

            string msg = "event:notificar\ndata:" + data + "\n\n";

            lstMensajes.Enqueue(msg);

            return "ok";

        }   

    }

}

Comentarios

Entradas populares de este blog

Web Scraping en Argentina: búsqueda de personas por DNI paso a paso

¡Mira Cómo Obtengo Datos de un Vehículo Solo con la Placa! (Web Scraping)

Bot whatsapp con whatsapp-web.js y nodejs