Menu
×
   ❮     
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS DSA TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI R GO KOTLIN SASS VUE GEN AI SCIPY CYBERSECURITY DATA SCIENCE INTRO TO PROGRAMMING BASH RUST

Node.js Tutorial

Node HOME Node Intro Node Get Started Node JS Requirements Node.js vs Browser Node Cmd Line Node V8 Engine Node Architecture Node Event Loop

Asynchronous

Node Async Node Promises Node Async/Await Node Errors Handling

Module Basics

Node Modules Node ES Modules Node NPM Node package.json Node NPM Scripts Node Manage Dep Node Publish Packages

Core Modules

HTTP Module HTTPS Module File System (fs) Path Module OS Module URL Module Events Module Stream Module Buffer Module Crypto Module Timers Module DNS Module Assert Module Util Module Readline Module

JS & TS Features

Node ES6+ Node Process Node TypeScript Node Adv. TypeScript Node Lint & Formatting

Building Applications

Node Frameworks Express.js Middleware Concept REST API Design API Authentication Node.js with Frontend

Database Integration

MySQL Get Started MySQL Create Database MySQL Create Table MySQL Insert Into MySQL Select From MySQL Where MySQL Order By MySQL Delete MySQL Drop Table MySQL Update MySQL Limit MySQL Join
MongoDB Get Started MongoDB Create DB MongoDB Collection MongoDB Insert MongoDB Find MongoDB Query MongoDB Sort MongoDB Delete MongoDB Drop Collection MongoDB Update MongoDB Limit MongoDB Join

Advanced Communication

GraphQL Socket.IO WebSockets

Testing & Debugging

Node Adv. Debugging Node Testing Apps Node Test Frameworks Node Test Runner

Node.js Deployment

Node Env Variables Node Dev vs Prod Node CI/CD Node Security Node Deployment

Perfomance & Scaling

Node Logging Node Monitoring Node Performance Child Process Module Cluster Module Worker Threads

Node.js Advanced

Microservices Node WebAssembly HTTP2 Module Perf_hooks Module VM Module TLS/SSL Module Net Module Zlib Module Real-World Examples

Hardware & IoT

RasPi Get Started RasPi GPIO Introduction RasPi Blinking LED RasPi LED & Pushbutton RasPi Flowing LEDs RasPi WebSocket RasPi RGB LED WebSocket RasPi Components

Node.js Reference

Built-in Modules EventEmitter (events) Worker (cluster) Cipher (crypto) Decipher (crypto) DiffieHellman (crypto) ECDH (crypto) Hash (crypto) Hmac (crypto) Sign (crypto) Verify (crypto) Socket (dgram, net, tls) ReadStream (fs, stream) WriteStream (fs, stream) Server (http, https, net, tls) Agent (http, https) Request (http) Response (http) Message (http) Interface (readline)

Resources & Tools

Node.js Compiler Node.js Server Node.js Quiz Node.js Exercises Node.js Syllabus Node.js Study Plan Node.js Certificate

Node.js HTTP/2 Module


What is HTTP/2?

The Node.js HTTP/2 module provides an implementation of the HTTP/2 protocol, offering improved performance, server push capabilities, header compression, and multiplexing over a single connection.

HTTP/2 improves upon HTTP/1.1 with several key features:

  • Binary protocol: HTTP/2 uses a binary format for data transfer rather than the text format of HTTP/1.1, making it more efficient to parse.
  • Multiplexing: Multiple requests and responses can be sent over a single connection simultaneously.
  • Header compression: HTTP/2 compresses headers to reduce overhead.
  • Server push: Servers can proactively send resources to clients before they request them.
  • Stream prioritization: Resources can be delivered with different priorities.

Using the HTTP/2 Module

In Node.js, the HTTP/2 module can be accessed using:

const http2 = require('http2');

The HTTP/2 module is stable as of Node.js v10.0.0. It's important to note that HTTP/2 requires a secure connection (HTTPS) in most browsers, so most examples will use TLS/SSL.


Creating an HTTP/2 Server

Here's an example of creating a basic HTTP/2 server using TLS:

const http2 = require('http2');
const fs = require('fs');
const path = require('path');

// Read the TLS certificate and key
const options = {
  key: fs.readFileSync(path.join(__dirname, 'server.key')),
  cert: fs.readFileSync(path.join(__dirname, 'server.crt'))
};

// Create an HTTP/2 server
const server = http2.createSecureServer(options);

// Handle stream events
server.on('stream', (stream, headers) => {
  // Get the path from headers
  const path = headers[':path'];
  
  // Send a response
  if (path === '/') {
    stream.respond({
      'content-type': 'text/html',
      ':status': 200
    });
    stream.end('<h1>Hello from HTTP/2!</h1>');
  } else {
    stream.respond({
      ':status': 404
    });
    stream.end('Not found');
  }
});

// Start the server
const port = 8080;
server.listen(port, () => {
  console.log(`HTTP/2 server running at https://localhost:${port}`);
});

This example assumes you have TLS certificate files. For development, you can generate self-signed certificates using OpenSSL. For production, use a trusted certificate authority.

You can also create an HTTP/2 server without TLS (for direct HTTP/2 connections without encryption):

const http2 = require('http2');

// Create an HTTP/2 server without TLS
const server = http2.createServer();

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html',
    ':status': 200
  });
  stream.end('<h1>Hello from HTTP/2 without TLS!</h1>');
});

server.listen(8080);

Most modern browsers only support HTTP/2 over TLS, so the insecure HTTP/2 server will typically only work with dedicated HTTP/2 clients that explicitly support cleartext HTTP/2.


HTTP/2 Client

Creating an HTTP/2 client to connect to an HTTP/2 server:

const http2 = require('http2');

// Create a client
const client = http2.connect('https://localhost:8080', {
  // For self-signed certificates in development
  rejectUnauthorized: false
});

// Error handling
client.on('error', (err) => {
  console.error('Client error:', err);
});

// Create a request
const req = client.request({ ':path': '/' });

// Handle response data
req.on('response', (headers) => {
  console.log('Status:', headers[':status']);
  console.log('Headers:', headers);
});

req.on('data', (chunk) => {
  console.log('Received data:', chunk.toString());
});

req.on('end', () => {
  console.log('Request completed');
  client.close();
});

// Send the request
req.end();

HTTP/2 Streams

HTTP/2 uses streams for communication between client and server. Each stream represents an independent, bidirectional sequence of frames exchanged between the client and server.

Stream Events

Important stream events include:

  • 'headers': Emitted when headers are received
  • 'data': Emitted when a chunk of data is received
  • 'end': Emitted when the stream is finished
  • 'error': Emitted when an error occurs
const http2 = require('http2');
const fs = require('fs');
const path = require('path');

// Create a server
const server = http2.createSecureServer({
  key: fs.readFileSync(path.join(__dirname, 'server.key')),
  cert: fs.readFileSync(path.join(__dirname, 'server.crt'))
});

server.on('stream', (stream, headers) => {
  // Handle stream events
  stream.on('error', (error) => {
    console.error('Stream error:', error);
  });
  
  stream.on('close', () => {
    console.log('Stream closed');
  });
  
  // Handle request
  stream.respond({
    'content-type': 'text/plain',
    ':status': 200
  });
  
  // Send data in multiple chunks
  stream.write('First chunk of data\n');
  
  setTimeout(() => {
    stream.write('Second chunk of data\n');
    stream.end('Final chunk of data');
  }, 1000);
});

server.listen(8080);

HTTP/2 Server Push

Server push allows the server to proactively send resources to the client before they are explicitly requested. This can improve performance by eliminating round-trip delays.

const http2 = require('http2');
const fs = require('fs');
const path = require('path');

const options = {
  key: fs.readFileSync(path.join(__dirname, 'server.key')),
  cert: fs.readFileSync(path.join(__dirname, 'server.crt'))
};

const server = http2.createSecureServer(options);

server.on('stream', (stream, headers) => {
  const requestPath = headers[':path'];
  
  if (requestPath === '/') {
    // Push CSS and JavaScript resources
    stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {
      if (err) {
        console.error('Error pushing stream:', err);
        return;
      }
      
      pushStream.respond({
        'content-type': 'text/css',
        ':status': 200
      });
      
      pushStream.end('body { color: blue; }');
    });
    
    stream.pushStream({ ':path': '/script.js' }, (err, pushStream) => {
      if (err) {
        console.error('Error pushing stream:', err);
        return;
      }
      
      pushStream.respond({
        'content-type': 'application/javascript',
        ':status': 200
      });
      
      pushStream.end('console.log("Hello from HTTP/2 server push!");');
    });
    
    // Send the main HTML document
    stream.respond({
      'content-type': 'text/html',
      ':status': 200
    });
    
    stream.end(`
      <!DOCTYPE html>
      <html>
      <head>
        <title>HTTP/2 Server Push Example</title>
        <link rel="stylesheet" href="/style.css">
        <script src="/script.js"></script>
      </head>
      <body>
        <h1>HTTP/2 Server Push Demo</h1>
        <p>CSS and JavaScript were pushed by the server!</p>
      </body>
    </html>
    `);
  } else {
    // Serve pushed resources if requested directly
    if (requestPath === '/style.css') {
      stream.respond({
        'content-type': 'text/css',
        ':status': 200
      });
      stream.end('body { color: blue; }');
    } else if (requestPath === '/script.js') {
      stream.respond({
        'content-type': 'application/javascript',
        ':status': 200
      });
      stream.end('console.log("Hello from HTTP/2 server push!");');
    } else {
      // Not found
      stream.respond({ ':status': 404 });
      stream.end('Not found');
    }
  }
});

server.listen(8080);

HTTP/2 Headers

HTTP/2 uses a different format for headers. Notably, all headers are lowercase, and request pseudo-headers start with a colon (:).

const http2 = require('http2');

// HTTP/2 pseudo-headers
const {
  HTTP2_HEADER_METHOD,
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_AUTHORITY,
  HTTP2_HEADER_SCHEME,
  HTTP2_HEADER_STATUS
} = http2.constants;

// Create a client
const client = http2.connect('https://localhost:8080', {
  rejectUnauthorized: false
});

// Send a request with custom headers
const req = client.request({
  [HTTP2_HEADER_METHOD]: 'GET',
  [HTTP2_HEADER_PATH]: '/',
  [HTTP2_HEADER_AUTHORITY]: 'localhost:8080',
  [HTTP2_HEADER_SCHEME]: 'https',
  'user-agent': 'node-http2/client',
  'custom-header': 'custom-value'
});

req.on('response', (headers) => {
  console.log('Response status:', headers[HTTP2_HEADER_STATUS]);
  console.log('Response headers:', headers);
});

req.on('data', (chunk) => {
  console.log('Received data:', chunk.toString());
});

req.on('end', () => {
  client.close();
});

req.end();

HTTP/2 Settings

HTTP/2 allows configuring various protocol settings:

const http2 = require('http2');
const fs = require('fs');
const path = require('path');

const options = {
  key: fs.readFileSync(path.join(__dirname, 'server.key')),
  cert: fs.readFileSync(path.join(__dirname, 'server.crt')),
  
  // HTTP/2 settings
  settings: {
    // Max concurrent streams per connection
    maxConcurrentStreams: 100,
    
    // Initial window size for flow control
    initialWindowSize: 1024 * 1024, // 1MB
    
    // Enable server push
    enablePush: true
  }
};

const server = http2.createSecureServer(options);

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html',
    ':status': 200
  });
  
  stream.end('<h1>HTTP/2 Server with Custom Settings</h1>');
});

server.listen(8080);

Compatibility with HTTP/1.1

HTTP/2 servers can also handle HTTP/1.1 requests, providing a seamless upgrade path:

const http2 = require('http2');
const http = require('http');
const fs = require('fs');
const path = require('path');

// For HTTP/2 secure server
const options = {
  key: fs.readFileSync(path.join(__dirname, 'server.key')),
  cert: fs.readFileSync(path.join(__dirname, 'server.crt')),
  allowHTTP1: true // Allow HTTP/1.1 connections
};

const server = http2.createSecureServer(options);

// Handler function for both HTTP/1.1 and HTTP/2
const handler = (req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end(`Hello from ${req.httpVersion} server!`);
};

// HTTP/1.1 compatibility request handler
server.on('request', handler);

// HTTP/2 specific stream handler
server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/plain',
    ':status': 200
  });
  stream.end(`Hello from HTTP/2 stream API!`);
});

server.listen(8080, () => {
  console.log('Server running at https://localhost:8080/');
});

Performance Considerations

While HTTP/2 offers performance improvements, it's important to optimize your usage:

  1. Connection Reuse - With HTTP/2, you should aim to use a single connection for multiple requests, rather than creating new connections.
  2. Proper Stream Management - Remember to close streams when they're no longer needed, and monitor the number of concurrent streams.
  3. Server Push Strategy - Only push resources that are likely to be needed. Excessive pushing can waste bandwidth and resources.
  4. Header Compression - Take advantage of HTTP/2's header compression by minimizing the number and size of custom headers.

HTTP/2 vs HTTP/1.1

Key differences between HTTP/2 and HTTP/1.1:

Feature HTTP/1.1 HTTP/2
Protocol Format Text-based Binary-based
Multiplexing No (requires multiple connections) Yes (multiple streams over one connection)
Header Compression None Yes (HPACK)
Server Push No Yes
Flow Control Basic Advanced, per-stream
Prioritization No Yes

Real-World Example: Serving a Complete Website

A complete example of serving a website with HTTP/2:

const http2 = require('http2');
const fs = require('fs');
const path = require('path');
const mime = require('mime-types');

const options = {
  key: fs.readFileSync(path.join(__dirname, 'server.key')),
  cert: fs.readFileSync(path.join(__dirname, 'server.crt'))
};

const server = http2.createSecureServer(options);

// Serve files from the public directory
const publicDir = path.join(__dirname, 'public');

server.on('stream', (stream, headers) => {
  const reqPath = headers[':path'] === '/' ? '/index.html' : headers[':path'];
  const filePath = path.join(publicDir, reqPath);
  
  // Basic security check to prevent path traversal
  if (!filePath.startsWith(publicDir)) {
    stream.respond({ ':status': 403 });
    stream.end('Forbidden');
    return;
  }
  
  fs.stat(filePath, (err, stats) => {
    if (err || !stats.isFile()) {
      // File not found
      stream.respond({ ':status': 404 });
      stream.end('Not found');
      return;
    }
    
    // Determine content type
    const contentType = mime.lookup(filePath) || 'application/octet-stream';
    
    // Serve the file
    stream.respond({
      'content-type': contentType,
      ':status': 200
    });
    
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(stream);
    
    fileStream.on('error', (err) => {
      console.error('File stream error:', err);
      stream.close(http2.constants.NGHTTP2_INTERNAL_ERROR);
    });
  });
});

server.listen(8080, () => {
  console.log('HTTP/2 server running at https://localhost:8080/');
});

This example requires the mime-types package:

npm install mime-types

Advanced Stream Management

HTTP/2's stream management capabilities allow for efficient handling of multiple concurrent requests. Here's an advanced example demonstrating stream prioritization and flow control:

const http2 = require('http2');
const fs = require('fs');

// Create a server with custom settings
const server = http2.createSecureServer({
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt'),
  settings: {
    initialWindowSize: 65535,  // 64KB initial window
    maxConcurrentStreams: 100,
    enablePush: true
  }
});

server.on('stream', (stream, headers) => {
  // Get priority information
  const weight = stream.priority && stream.priority.weight || 1;
  const parent = stream.priority && stream.priority.parent ? 'with parent' : 'no parent';
  
  console.log(`New stream ${stream.id} (weight: ${weight}, ${parent})`);
  
  // Handle different priority levels
  if (headers[':path'] === '/high-priority') {
    stream.priority({ weight: 256, exclusive: true });
    stream.respond({ ':status': 200, 'content-type': 'text/plain' });
    stream.end('High priority content');
  } else {
    // Default priority
    stream.respond({ ':status': 200, 'content-type': 'text/plain' });
    stream.end('Standard priority content');
  }
  
  // Handle stream errors
  stream.on('error', (error) => {
    console.error(`Stream ${stream.id} error:`, error);
    stream.end();
  });
  
  // Handle stream close
  stream.on('close', () => {
    console.log(`Stream ${stream.id} closed`);
  });
});

server.listen(8443);

Error Handling and Debugging

Proper error handling is crucial for reliable HTTP/2 applications. Here's how to implement comprehensive error handling:

const http2 = require('http2');
const fs = require('fs');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);

async function startServer() {
  try {
    const [key, cert] = await Promise.all([
      readFile('server.key'),
      readFile('server.crt')
    ]);

    const server = http2.createSecureServer({ key, cert });
    
    // Global error handler
    server.on('error', (err) => {
      console.error('Server error:', err);
      // Implement proper error recovery
    });
    
    // Handle uncaught exceptions
    process.on('uncaughtException', (err) => {
      console.error('Uncaught exception:', err);
      // Graceful shutdown
      server.close(() => process.exit(1));
    });
    
    // Handle unhandled promise rejections
    process.on('unhandledRejection', (reason, promise) => {
      console.error('Unhandled Rejection at:', promise, 'reason:', reason);
    });
    
    // Stream handler with error boundaries
    server.on('stream', (stream, headers) => {
      try {
        // Simulate async operation
        setTimeout(() => {
          try {
            if (Math.random() > 0.8) {
              throw new Error('Random error for demonstration');
            }
            stream.respond({ ':status': 200 });
            stream.end('Success!');
          } catch (err) {
            handleStreamError(stream, err);
          }
        }, 100);
      } catch (err) {
        handleStreamError(stream, err);
      }
    });
    
    function handleStreamError(stream, error) {
      console.error('Stream error:', error);
      if (!stream.destroyed) {
        stream.respond({
          ':status': 500,
          'content-type': 'text/plain'
        });
        stream.end('Internal Server Error');
      }
    }
    
    server.listen(8443, () => {
      console.log('Server running on https://localhost:8443');
    });
    
  } catch (err) {
    console.error('Failed to start server:', err);
    process.exit(1);
  }
}

startServer();

Performance Optimization

Optimizing HTTP/2 performance requires understanding its unique characteristics. Here are key strategies:

1. Connection Pooling

const http2 = require('http2');
const { URL } = require('url');

class HTTP2ConnectionPool {
  constructor() {
    this.connections = new Map();
  }
  
  async getConnection(url) {
    const { origin } = new URL(url);
    
    if (!this.connections.has(origin)) {
      const client = http2.connect(origin, {
        rejectUnauthorized: false // Only for development
      });
      
      // Handle connection errors
      client.on('error', (err) => {
        console.error('Connection error:', err);
        this.connections.delete(origin);
      });
      
      // Remove connection when closed
      client.on('close', () => {
        this.connections.delete(origin);
      });
      
      this.connections.set(origin, {
        client,
        lastUsed: Date.now(),
        inUse: 0
      });
    }
    
    const conn = this.connections.get(origin);
    conn.lastUsed = Date.now();
    conn.inUse++;
    
    return {
      client: conn.client,
      release: () => {
        conn.inUse--;
      }
    };
  }
  
  // Clean up idle connections
  startCleanup(interval = 30000) {
    setInterval(() => {
      const now = Date.now();
      for (const [origin, conn] of this.connections.entries()) {
        if (conn.inUse === 0 && (now - conn.lastUsed) > 60000) {
          conn.client.destroy();
          this.connections.delete(origin);
        }
      }
    }, interval);
  }
}

// Usage example
const pool = new HTTP2ConnectionPool();
pool.startCleanup();

async function makeRequest(url) {
  const { client, release } = await pool.getConnection(url);
  return new Promise((resolve, reject) => {
    const req = client.request({ ':path': new URL(url).pathname });
    let data = '';
    
    req.on('response', (headers) => {
      console.log('Status:', headers[':status']);
    });
    
    req.on('data', (chunk) => data += chunk);
    req.on('end', () => {
      release();
      resolve(data);
    });
    req.on('error', (err) => {
      release();
      reject(err);
    });
    
    req.end();
  });
}

2. Header Compression Optimization

HTTP/2 uses HPACK compression for headers. Optimize by:

  • Minimizing cookie sizes
  • Using short but descriptive header names
  • Avoiding duplicate headers
  • Using HTTP/2-specific headers when possible

Security Best Practices

When using HTTP/2, follow these security practices:

const http2 = require('http2');
const fs = require('fs');
const { createSecureContext } = require('tls');

// Security headers middleware
function securityHeaders(req, res, next) {
  // Set security headers
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  res.setHeader('Content-Security-Policy', "default-src 'self'");
  
  // Remove server header
  res.removeHeader('X-Powered-By');
  
  next();
}

// Create secure server with modern TLS settings
const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt'),
  secureOptions:
    require('constants').SSL_OP_NO_SSLv3 |
    require('constants').SSL_OP_NO_TLSv1 |
    require('constants').SSL_OP_NO_TLSv1_1,
  ciphers: [
    'TLS_AES_256_GCM_SHA384',
    'TLS_CHACHA20_POLY1305_SHA256',
    'TLS_AES_128_GCM_SHA256'
  ].join(':'),
  minVersion: 'TLSv1.3',
  maxVersion: 'TLSv1.3',
  // OCSP Stapling
  requestCert: false,
  rejectUnauthorized: true
};

const server = http2.createSecureServer(options);

// Apply security middleware
server.on('request', (req, res) => {
  securityHeaders(req, res, () => {
    // Request handling logic
    res.setHeader('Content-Type', 'text/plain');
    res.end('Secure HTTP/2 Response');
  });
});

// Handle TLS errors
server.on('tlsClientError', (err, tlsSocket) => {
  console.error('TLS Error:', err);
  tlsSocket.destroy();
});

server.listen(8443);

Real-World Use Cases

1. API Gateway with HTTP/2

Building a high-performance API gateway with HTTP/2:

const http2 = require('http2');
const { URL } = require('url');
const path = require('path');
const fs = require('fs');

// Service registry
const services = {
  '/users': 'http://users-service:3000',
  '/products': 'http://products-service:3000',
  '/orders': 'http://orders-service:3000'
};

// Create HTTP/2 server
const server = http2.createSecureServer({
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
});

// Route requests to appropriate services
server.on('stream', (stream, headers) => {
  const path = headers[':path'];
  const method = headers[':method'];
  
  try {
    // Find matching service
    const servicePath = Object.keys(services).find(prefix =>
      path.startsWith(prefix)
    );
    
    if (!servicePath) {
      stream.respond({ ':status': 404 });
      return stream.end('Not Found');
    }
    
    const targetUrl = new URL(path.slice(servicePath.length), services[servicePath]);
    
    // Forward request to target service
    const client = http2.connect(targetUrl.origin);
    const req = client.request({
      ...headers,
      ':path': targetUrl.pathname + targetUrl.search,
      ':method': method,
      ':authority': targetUrl.host
    });
    
    // Pipe the response back to client
    req.pipe(stream);
    stream.pipe(req);
    
    // Handle errors
    req.on('error', (err) => {
      console.error('Request error:', err);
      if (!stream.destroyed) {
        stream.respond({ ':status': 502 });
        stream.end('Bad Gateway');
      }
    });
    
    stream.on('error', (err) => {
      console.error('Stream error:', err);
      req.destroy();
    });
    
  } catch (err) {
    console.error('Gateway error:', err);
    if (!stream.destroyed) {
      stream.respond({ ':status': 500 });
      stream.end('Internal Server Error');
    }
  }
});

server.listen(443);

2. Real-Time Data Streaming

Efficient real-time data streaming with HTTP/2:

const http2 = require('http2');
const fs = require('fs');

const server = http2.createSecureServer({
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
});

// In-memory storage for active streams
const streams = new Set();

// Broadcast data to all connected clients
function broadcast(data) {
  const payload = JSON.stringify(data);
  for (const stream of streams) {
    try {
      stream.write(`data: ${payload}\n\n`);
    } catch (err) {
      console.error('Stream write error:', err);
      streams.delete(stream);
    }
  }
}

// Simulate data updates
setInterval(() => {
  broadcast({
    time: new Date().toISOString(),
    value: Math.random() * 100
  });
}, 1000);

server.on('stream', (stream, headers) => {
  // Only handle GET requests
  if (headers[':method'] !== 'GET') {
    stream.respond({ ':status': 405 });
    return stream.end();
  }
  
  // Set up Server-Sent Events headers
  stream.respond({
    'content-type': 'text/event-stream',
    'cache-control': 'no-cache',
    'connection': 'keep-alive',
    ':status': 200
  });
  
  // Add to active streams
  streams.add(stream);
  
  // Handle client disconnect
  stream.on('close', () => {
    streams.delete(stream);
  });
  
  // Send initial data
  stream.write('event: connect\ndata: Connected\n\n');
});

server.listen(8443, () => {
  console.log('HTTP/2 Server running on https://localhost:8443');
});


×

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail:
sales@w3schools.com

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail:
help@w3schools.com

W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 1999-2025 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS.