xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

Node.js SSE in Action All In One

Node.js SSE in Action All In One

Node.js & Server-sent events

SSE

Server-sent events: method of continuously sending data from a server to the browser, rather than repeatedly requesting it (EventSource interface, used to fall under HTML5)

image

https://caniuse.com/eventsource

var source = new EventSource('updates.cgi');
source.onmessage = function (event) {
  alert(event.data);
};
var source = new EventSource('updates.cgi');
source.addEventListener('add', addHandler, false);
source.addEventListener('remove', removeHandler, false);

https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events

EventSource

⚠️ Warning: When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be specially painful when opening various tabs as the limit is per browser and set to a very low number (6).
The issue has been marked as "Won't fix" in Chrome and Firefox.
This limit is per browser + domain, so that means that you can open 6 SSE connections across all of the tabs to www.example1.com and another 6 SSE connections to www.example2.com.
When using HTTP/2, the maximum number of simultaneous HTTP streams is negotiated between the server and the client (defaults to 100).

const evtSource = new EventSource("sse.php");
const eventList = document.querySelector("ul");

evtSource.onmessage = (e) => {
  const newElement = document.createElement("li");
  newElement.textContent = `message: ${e.data}`;
  eventList.appendChild(newElement);
};


https://developer.mozilla.org/en-US/docs/Web/API/EventSource

demos

server.js

// const express = require('express')
// const fs = require('fs')

import fs from 'node:fs';
import express from 'express';

const app = express();
app.use(express.static('public'));

// const convertImageToBase64URL = (filename, imageType = 'png') => {
//   try {
//     const base64String = fs.readFileSync(filename, {
//       encoding: 'base64',
//     });
//     console.log(`base64String`, base64String.slice(0, 100));
//     return `data:image/${imageType};base64,${base64String}`;
//   } catch (error) {
//     throw new Error(`file ${filename} no exist ❌`)
//   }
// }

const convertImageToBase64URL = (filename, imageType = 'png') => {
  try {
    const buffer = fs.readFileSync(filename);
    const base64String = Buffer.from(buffer).toString('base64');
    // console.log(`base64String`, base64String.slice(0, 100));
    return `data:image/${imageType};base64,${base64String}`;
  } catch (error) {
    throw new Error(`file ${filename} no exist ❌`)
  }
}

app.get('/img', (req, res) => {
  // res.writeHead(200, {
  //   // 'Content-Type': 'image/jpg;base64',
  //   // 'Content-Type': 'image/png;base64',
  //   'Content-Type': 'application/json',
  //   'Cache-Control': 'no-cache',
  //   'Connection': 'keep-alive',
  // });
  const data = convertImageToBase64URL("./public/test.png");
  // console.log(`base64String`, data.slice(0, 100));
  res.json({
    data,
  });
  // res.write(data);
});
// http://localhost:3000/img

// app.get('/', (req, res) => {
//   res.file(`/public/index.html`);
// });
// http://localhost:3000/

const port = 3000;
app.listen(port, () => {
  console.log(`SSE server is running on: http://localhost:${port}/`);
});


<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="author" content="xgqfrms">
  <meta name="generator" content="VS code">
  <title>Node.js SSE</title>
  <script src="./client.js"></script>
</head>
<body>
  <header>
    <h1>Node.js SSE</h1>
  </header>
  <main>
    <img id="img" src="" />
    <!-- <img id="img" src="http://localhost:3000/img" /> -->
  </main>
  <footer>
    <p>copyright&copy; xgqfrms 2022</p>
  </footer>
  <!-- <script type="module" src="./client.js"></script> -->
  <script>
    window.addEventListener(`load`, (event) => {
      console.log(`page loaded ✅`);
      fetch(`http://localhost:3000/img`)
      .then(res => res.json())
      .then(json => {
        console.log(`json`, json);
        const img = document.querySelector(`#img`);
        // img.src = `data:image/png;base64,${json.data}`;
        img.src = json.data;
      });
    });
  </script>
</body>
</html>

client.js

    window.addEventListener(`load`, (event) => {
      console.log(`page loaded ✅`);
      fetch(`http://localhost:3000/img`)
      .then(res => res.json())
      .then(json => {
        console.log(`json`, json);
        const img = document.querySelector(`#img`);
        // img.src = `data:image/png;base64,${json.data}`;
        img.src = json.data;
      });
    });
document.addEventListener(`DOMContentLoad`, (event) => {
  console.log(`DOM fully loaded and parsed ✅`);
  if (!!window.EventSource) {
    const img = document.querySelector(`#img`);
    // const source = new EventSource('/img');
    const source = new EventSource('http://localhost:3000/img');
    source.onopen = (e) => {
      console.log(`✅ Connection to server opened.`, e);
    };
    source.message = (e) => {
      const data = e.data;
      console.log(`🚀 data =`, data)
      // img.src = `data:image/jpg;base64,${data}`;
      // img.src = `data:image/png;base64,${data}`;
      img.src = `${data}`;
    };
    // source.addEventListener(`message`, (e) => {
    //   const data = e.data;
    //   console.log(`data =`, data)
    //   img.src = `data:image/png;base64,${data}`;
    // }, false);
    source.onerror = (err) => {
      console.log(`❌ EventSource failed.`, err);
      setTimeout(() => {
        console.log(`⚠️ After 3 seconds, auto close connection!`);
        source.close();
      }, 3000);
    };
  } else {
    console.log(`Your browser doesn't support SSE ❌`);
  }
});

custom event type

server.js

app.get('/sse', (req, res) => {
  res.writeHead(200, {
    // 'Content-Type': 'image/jpg',
    // 'Content-Type': 'image/png',
    //   'Content-Type': 'application/json',
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    // 'CharacterEncoding': 'UTF-8',
    // 'Accept-Encoding': 'UTF-8',
  });
  // response.setContentType("text/event-stream");
  // response.setCharacterEncoding("UTF-8");
  // const data = convertImageToBase64URL("./public/test.png");
  // console.log(`SSE`, data.slice(0, 100));
  // res.write(data);
  let i = 0;
  let uid = setInterval(() => {
    console.log(`i`, i);
    if(i < 10) {
      i++;
      const data = convertImageToBase64URL("./public/test.png");
      console.log(`SSE ${i}`, data.slice(0, 100));
      // ❌
      // res.write(data);
      // ✅ 使用 \n\n 换行符号,标识 stream 结束 ❓
      // event type `message` \n
      // event data `data` \n\n
      // res.write(`event: message\n`);
      // custom event type `custom_message`\n ✅
      res.write(`event: custom_event_message\n`);
      res.write(`data: ${data}\n\n`);
    } else {
      clearInterval(uid);
      res.end();
    }
  }, 3000);
});
// http://localhost:3000/sse

client.js

window.addEventListener(`load`, (e) => {
  console.log(`page loaded ✅`);
  if (!!window.EventSource) {
    const img = document.querySelector(`#sse`);
    const source = new EventSource('http://localhost:3000/sse');
    source.onopen = (event) => {
      console.log(`✅ Connection to server opened.`, event);
    };
    // ✅ default event type `message` 可以使用 `onmessage` / addEventListener(`message`
    // source.onmessage = (event) => {
    //   console.log(`event`, event);
    //   const type = event.type;
    //   console.log(`event.type`, type);
    //   const data = event.data;
    //   console.log(`🚀 event.data =`, data)
    //   // img.src = `data:image/jpg;base64,${data}`;
    //   // img.src = `data:image/png;base64,${data}`;
    //   img.src = `${data}`;
    // };
    source.addEventListener(`message`, (event) => {
      console.log(`event`, event);
      const type = event.type;
      console.log(`event.type`, type);
      const data = event.data;
      console.log(`🚀 event.data =`, data)
      // img.src = `data:image/jpg;base64,${data}`;
      // img.src = `data:image/png;base64,${data}`;
      img.src = `${data}`;
    });
    // ❌ custom event message 不可以使用 `onmessage`
    // source.oncustom_event_message = (event) => {
    // ✅ custom event message 只可以使用 addEventListener(`custom_event_message`
    source.addEventListener(`custom_event_message`, (event) => {
      console.log(`event`, event);
      const type = event.type;
      console.log(`event.type`, type);
      const data = event.data;
      console.log(`🚀 event.data =`, data)
      // img.src = `data:image/jpg;base64,${data}`;
      // img.src = `data:image/png;base64,${data}`;
      img.src = `${data}`;
    });
    source.onerror = (err) => {
      console.log(`❌ EventSource failed.`, err);
      // setTimeout(() => {
      //   console.log(`⚠️ After 3 seconds, auto close connection!`);
      //   source.close();
      // }, 3000);
    };
  } else {
    console.log(`Your browser doesn't support SSE ❌`);
  }
});

image

(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 https://www.cnblogs.com/xgqfrms/ 查看原创文章!

Node.js image generator

https://www.npmjs.com/package/js-image-generator

https://www.npmjs.com/package/pureimage

Node.js convert image to base64 string

https://www.npmjs.com/package/image-to-base64

Node.js Buffer.from All In One

https://www.cnblogs.com/xgqfrms/p/17357737.html

refs

How to fix EventSource onmessage not working in JavaScript All In One

https://www.cnblogs.com/xgqfrms/p/17783689.html

https://stackoverflow.com/questions/77341435/nodejs-sending-image-files-using-sse/77342298#77342298

https://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource/5326159

res.end();

https://stackoverflow.com/questions/36249684/simple-way-to-implement-server-sent-events-in-node-js/50594265#50594265



©xgqfrms 2012-2021

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @ 2023-10-23 09:30  xgqfrms  阅读(49)  评论(2编辑  收藏  举报