Loading lesson path
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.
Formula
HTTP/2 improves upon HTTP/1.1 with several key features:: HTTP/2 uses a binary format for data transfer rather than the text format of HTTP/1.1, making it more efficient to parse.
: Multiple requests and responses can be sent over a single connection simultaneously.
Formula
: HTTP/2 compresses headers to reduce overhead.: Servers can proactively send resources to clients before they request them.
: Resources can be delivered with different priorities.
Formula
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.Formula
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) => {Formula
// Get the path from headers const path = headers[':path'];// Send a response if (path === '/') {
stream.respond({Formula
'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.
Formula
You can also create an HTTP/2 server without TLS (for direct HTTP/2 connections without encryption):const http2 = require('http2');Formula
// Create an HTTP/2 server without TLSconst server = http2.createServer();
server.on('stream', (stream, headers) => {
stream.respond({Formula
'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.
Formula
Creating an HTTP/2 client to connect to an HTTP/2 server:const http2 = require('http2');Formula
// 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);
});Formula
// 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 uses streams for communication between client and server. Each stream represents an independent, bidirectional sequence of frames exchanged between the client and server.
'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({Formula
'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);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({Formula
'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({Formula
'content - type': 'application/javascript',':status': 200
});
pushStream.end('console.log("Hello from HTTP/2 server push!");');
});
// Send the main HTML document stream.respond({Formula
'content - type': 'text/html',':status': 200
});
stream.end(`<!DOCTYPE html> <html> <head>
Formula
< title > HTTP/2 Server Push Example </title ><link rel="stylesheet" href="/style.css"> <script src="/script.js"></script> </head> <body>
Formula
< 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({Formula
'content - type': 'text/css',':status': 200
});
stream.end('body { color: blue; }');
} else if (requestPath === '/script.js') {
stream.respond({Formula
'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 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;Formula
// 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',Formula
'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();Formula
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')),Formula
// HTTP/2 settings settings: {// Max concurrent streams per connection maxConcurrentStreams: 100,
Formula
// 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({Formula
'content - type': 'text/html',':status': 200
});
stream.end('<h1>HTTP/2 Server with Custom Settings</h1>');
});
server.listen(8080);Formula
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({Formula
'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/');
});Formula
While HTTP/2 offers performance improvements, it's important to optimize your usage:Formula
- With HTTP/2, you should aim to use a single connection for multiple requests, rather than creating new connections.Formula
- 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:Formula
HTTP/1.1