🌐 Detecting your location…

Node.js में सर्वर-भेजे गए ईवेंट को कैसे कार्यान्वित करें और 2026 में प्रतिक्रिया दें: संपूर्ण मार्गदर्शिका

⏱️3 min read  ·  605 words

सर्वर-भेजे गए इवेंट डेटा को सर्वर से ब्राउज़र तक भेजने का सबसे सरल तरीका है। वे सामान्य HTTP पर चलते हैं, स्वचालित रूप से पुन: कनेक्ट होते हैं, और किसी अतिरिक्त प्रोटोकॉल की आवश्यकता नहीं होती है। डैशबोर्ड, नोटिफिकेशन, प्रगति अपडेट और स्ट्रीमिंग एआई प्रतिक्रियाओं के लिए – कुछ भी जहां डेटा एक तरफ प्रवाहित होता है – एसएसई आमतौर पर वेबसॉकेट पर सही विकल्प है।

एसएसई या वेबसॉकेट?

एसएसई वेबसॉकेट
दिशा केवल क्लाइंट के लिए सर्वर द्विदिश
प्रोटोकॉल सादा HTTP ws://
पर अपग्रेड करें स्वतः पुनः कनेक्ट में निर्मित आप इसे लागू करें
डेटा प्रारूप यूटीएफ-8 टेक्स्ट टेक्स्ट या बाइनरी
प्रॉक्सी मित्रता आमतौर पर ठीक अपग्रेड समर्थन की आवश्यकता है
जटिलता निम्न उच्चतर

का प्रयोग करें एसएसई लाइव डैशबोर्ड, अधिसूचना फ़ीड, कार्य प्रगति, लॉग टेलिंग और टोकन-दर-टोकन एआई आउटपुट के लिए।का प्रयोग करें वेबसॉकेट जब ग्राहक लगातार संदेश भी भेजता है – चैट, सहयोगात्मक संपादन, मल्टीप्लेयर गेम।एक सामान्य और समझदार हाइब्रिड: सर्वर अपडेट के लिए एसएसई, क्लाइंट क्रियाओं के लिए सामान्य HTTP POST अनुरोध। इसमें दूसरे प्रोटोकॉल के बिना अधिकांश एप्लिकेशन शामिल हैं।

तार प्रारूप

एसएसई एक छोटे, सख्त प्रारूप वाली एक सादा पाठ स्ट्रीम है।

दो नियम लगभग हर बग का कारण बनते हैं। प्रत्येक संदेश

data: hello world

event: userUpdate
data: {"id":1,"name":"Ada"}

id: 42
retry: 5000
data: message with an id and a retry hint

के साथ समाप्त होता है दो नई पंक्तियाँ और मल्टी-लाइन डेटा कोकी आवश्यकता होती है प्रत्येक पंक्ति पर उपसर्ग, यही कारण है कि JSON पेलोड में कच्ची नई पंक्तियाँ नहीं होनी चाहिए।data:सर्वर: एक्सप्रेस के साथ Node.js

यहां तीन विवरण मायने रखते हैं।

import express from 'express';

const app = express();

// Track connected clients so we can broadcast.
const clients = new Set();

app.get('/api/events', (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache, no-transform',
    'Connection': 'keep-alive',
    // Tell nginx not to buffer this response.
    'X-Accel-Buffering': 'no',
  });

  // Flush headers immediately so the client's connection opens.
  res.flushHeaders();

  const client = { id: Date.now(), res };
  clients.add(client);

  send(res, { type: 'connected', at: new Date().toISOString() });

  // A comment line every 25s keeps proxies from closing an idle connection.
  const heartbeat = setInterval(() => {
    res.write(': heartbeat\n\n');
  }, 25_000);

  req.on('close', () => {
    clearInterval(heartbeat);
    clients.delete(client);
  });
});

function send(res, data, event) {
  if (event) res.write(`event: ${event}\n`);
  // JSON.stringify never emits a raw newline, which keeps the frame valid.
  res.write(`data: ${JSON.stringify(data)}\n\n`);
}

export function broadcast(data, event) {
  for (const client of clients) {
    send(client.res, data, event);
  }
}

app.listen(3000);

पहली बार लिखने की प्रतीक्षा करने के बजाय तुरंत स्ट्रीम खोलता है। दिल की धड़कन की टिप्पणी मध्यस्थों को निष्क्रिय कनेक्शन छोड़ने से रोकती है। औरflushHeaders() nginx को प्रतिक्रिया को बफर करने से रोकता है, जो SSE के स्थानीय स्तर पर काम करने और उत्पादन में विफल होने का सबसे आम कारण है।X-Accel-Buffering: noग्राहक: प्रतिक्रिया

लौट रहा हूँ

import { useEffect, useRef, useState } from 'react';

export function useEventStream(url) {
  const [messages, setMessages] = useState([]);
  const [status, setStatus] = useState('connecting');
  const sourceRef = useRef(null);

  useEffect(() => {
    const source = new EventSource(url, { withCredentials: true });
    sourceRef.current = source;

    source.onopen = () => setStatus('open');

    source.onmessage = (e) => {
      const data = JSON.parse(e.data);
      setMessages(prev => [...prev, data]);
    };

    // Named events need their own listener.
    source.addEventListener('userUpdate', (e) => {
      const data = JSON.parse(e.data);
      setMessages(prev => [...prev, { ...data, kind: 'userUpdate' }]);
    });

    source.onerror = () => {
      // EventSource reconnects on its own unless the state is CLOSED.
      setStatus(source.readyState === EventSource.CLOSED ? 'closed' : 'reconnecting');
    };

    return () => source.close();
  }, [url]);

  return { messages, status };
}
export function LiveFeed() {
  const { messages, status } = useEventStream('/api/events');

  return (
    <div>
      <p>Status: {status}</p>
      <ul>
        {messages.map((m, i) => <li key={i}>{JSON.stringify(m)}</li>)}
      </ul>
    </div>
  );
}

प्रभाव से वैकल्पिक नहीं है. इसके बिना, रिएक्ट स्ट्रिक्ट मोड का डबल-माउंट एक अनाथ कनेक्शन छोड़ देता है, और ऐप के चारों ओर नेविगेट करने से ब्राउज़र की प्रति-डोमेन कनेक्शन सीमा तक पहुंचने तक खुली स्ट्रीम जमा हो जाती है और सब कुछ रुक जाता है।source.close()डिस्कनेक्ट के बाद फिर से शुरू करना

जब आप

भेजते हैं फ़ील्ड, ब्राउज़र इसे संग्रहीत करता है और इसेid:के रूप में वापस भेजता है पुनः जुड़ने पर. इससे आपको केवल वही दोबारा खेलने की सुविधा मिलती है जो छूट गया था।Last-Event-IDयह एसएसई को सर्वोत्तम प्रयास से विश्वसनीय डिलीवरी के करीब ले जाता है, जो अधिसूचना फ़ीड के लिए मायने रखता है जहां एक गिरा हुआ संदेश उपयोगकर्ता को दिखाई देता है।

app.get('/api/events', (req, res) => {
  // ... headers as above ...

  const lastId = req.headers['last-event-id'];
  if (lastId) {
    for (const event of getEventsSince(Number(lastId))) {
      res.write(`id: ${event.id}\n`);
      res.write(`data: ${JSON.stringify(event.payload)}\n\n`);
    }
  }
});

प्रमाणीकरण

मूलनिवासी

एपीआई कस्टम हेडर सेट नहीं कर सकता है, जो टोकन-प्रमाणीकृत एपीआई बनाने वाले लोगों को आश्चर्यचकित करता है। तीन व्यावहारिक दृष्टिकोण:EventSourceकुकीज़

– सरलतम. पास और सत्र कुकी को किसी अन्य अनुरोध की तरह ही अनुरोध को प्रमाणित करने दें।withCredentials: trueक्वेरी स्ट्रिंग में एक अल्पकालिक टोकन

– केवल तभी स्वीकार्य है जब टोकन एकल-उपयोग है और मिनटों में समाप्त हो जाता है, क्योंकि यूआरएल सर्वर लॉग में समाप्त हो जाते हैं।स्ट्रीमिंग रीडर के साथ प्राप्त करें

– पूर्ण हेडर नियंत्रण, स्वयं पुन: संयोजन लागू करने की कीमत पर।बफ़रिंग पर ध्यान दें: एक नेटवर्क हिस्सा एक फ़्रेम को आधे में विभाजित कर सकता है, इसलिए आपको शेष रखना होगा और केवल पूर्ण फ़्रेम को पार्स करना होगा। प्रत्येक खंड को स्वतंत्र रूप से पार्स करने से रुक-रुक कर JSON त्रुटियाँ उत्पन्न होती हैं जिनका निदान करना दर्दनाक होता है।

async function streamWithAuth(url, token, onMessage) {
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` },
  });

  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const frames = buffer.split('\n\n');
    buffer = frames.pop() ?? '';       // keep the incomplete frame

    for (const frame of frames) {
      const line = frame.split('\n').find(l => l.startsWith('data:'));
      if (line) onMessage(JSON.parse(line.slice(5).trim()));
    }
  }
}

स्ट्रीमिंग एआई प्रतिक्रियाएँ

चैट इंटरफेस में टोकन-दर-टोकन आउटपुट के पीछे का पैटर्न।

प्रॉक्सी और परिनियोजन कॉन्फ़िगरेशन

app.post('/api/chat', async (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache, no-transform',
    'X-Accel-Buffering': 'no',
  });
  res.flushHeaders();

  try {
    for await (const chunk of generateResponse(req.body.prompt)) {
      res.write(`data: ${JSON.stringify({ token: chunk })}\n\n`);
    }
    res.write('data: [DONE]\n\n');
  } catch (err) {
    res.write(`event: error\ndata: ${JSON.stringify({ message: err.message })}\n\n`);
  } finally {
    res.end();
  }
});

अधिकांश उत्पादन SSE विफलताएँ प्रॉक्सी बफ़रिंग हैं। केवल हेडर ही हमेशा पर्याप्त नहीं होता.

यह भी ध्यान रखें कि सर्वर रहित प्लेटफ़ॉर्म अक्सर प्रतिक्रिया अवधि को सीमित कर देते हैं, जो लंबे समय तक चलने वाले एसएसई कनेक्शन को अनुपयुक्त बना देता है। अपने प्लेटफ़ॉर्म के चारों ओर डिज़ाइन करने से पहले उसकी सीमा की जाँच करें। और HTTP/1.1 के साथ, ब्राउज़र प्रति डोमेन केवल छह कनेक्शन की अनुमति देते हैं – HTTP/2 उस बाधा को हटा देता है, इसलिए जहां भी आप कर सकते हैं HTTP/2 पर SSE की सेवा करें।

# nginx
location /api/events {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Connection '';
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 24h;
    chunked_transfer_encoding off;
}

सामान्य गलतियाँ

दूसरी नई पंक्ति को भूल जाना.

संदेश कभी प्रेषित नहीं होता और क्लाइंट हैंग होता प्रतीत होता है।अनमाउंट पर इवेंटसोर्स को बंद नहीं किया जा रहा है।

ब्राउज़र की सीमा समाप्त होने तक कनेक्शन जमा होते रहते हैं।डेटा के अंदर कच्ची नई पंक्तियाँ।

हमेशा पेलोड.JSON.stringifyकोई दिल की धड़कन नहीं.

निष्क्रिय कनेक्शन एक-दो मिनट बाद बिचौलियों द्वारा बंद कर दिए जाते हैं।प्रॉक्सी बफ़रिंग चालू छोड़ दी गई है।

सब कुछ स्थानीय रूप से काम करता है, फिर प्रतिक्रिया समाप्त होने तक उत्पादन में कुछ भी नहीं आता है।द्विदिशीय यातायात के लिए SSE का उपयोग करना।

यदि क्लाइंट बार-बार संदेश भेजता है, तो WebSockets का उपयोग करें।निष्कर्ष

एसएसई आपको स्वचालित पुन: कनेक्शन और बहुत कम कोड के साथ सामान्य HTTP पर सर्वर-टू-क्लाइंट स्ट्रीमिंग प्रदान करता है। पाँच चीज़ें ठीक से प्राप्त करें:

एसएसई आपको स्वचालित पुन: कनेक्शन और बहुत कम कोड के साथ सामान्य HTTP पर सर्वर-टू-क्लाइंट स्ट्रीमिंग प्रदान करता है। पाँच चीज़ें ठीक से प्राप्त करें:प्रत्येक संदेश को दो नई पंक्तियों के साथ समाप्त करें, एक आवधिक दिल की धड़कन टिप्पणी भेजें, हेडर और nginx कॉन्फ़िगरेशन दोनों के साथ प्रॉक्सी बफरिंग अक्षम करें, अपने प्रभाव क्लीनअप में इवेंटसोर्स को बंद करें, औरid:का उपयोग करें Last-Event-IDके साथ जब छूटे हुए संदेशों पर ध्यान दिया जाएगा। वेबसॉकेट के लिए तभी पहुंचें जब क्लाइंट को वास्तव में बार-बार संदेश भेजने की आवश्यकता हो।

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা