What is HTTP2 support in Node.js?
HTTP/2 is a major revision of the HTTP network protocol, offering significant performance improvements over HTTP/1.1. Node.js provides built-in, first-class support for HTTP/2 through its `http2` module, allowing developers to easily build high-performance web applications and services.
Key Features and Benefits of HTTP/2
- Multiplexing: Allows multiple requests and responses to be sent over a single TCP connection concurrently, eliminating head-of-line blocking.
- Header Compression (HPACK): Reduces overhead by compressing HTTP header fields, especially beneficial for applications with many small requests.
- Server Push: Enables servers to proactively send resources (e.g., CSS, JavaScript, images) to clients that it anticipates will be needed, without the client explicitly requesting them.
- Binary Protocol: Unlike HTTP/1.1's text-based protocol, HTTP/2 is binary, which is more efficient to parse and less error-prone.
- Stream Prioritization: Clients can assign priorities to streams, indicating which resources are more important for the server to send first.
How to Use HTTP/2 in Node.js
Node.js offers the http2 module, which can be used to create both secure (HTTPS/2) and insecure (HTTP/2) servers and clients. In practice, HTTP/2 is almost exclusively used over TLS (HTTPS) to ensure security and browser compatibility.
Creating an HTTP/2 Server
To create a secure HTTP/2 server, you'll need SSL/TLS certificates. You can generate self-signed certificates for development or use certificates from a trusted CA for production.
const http2 = require('http2');
const fs = require('fs');
// For development, you can generate self-signed certs
const options = {
key: fs.readFileSync('path/to/server.key'),
cert: fs.readFileSync('path/to/server.crt')
};
const server = http2.createSecureServer(options, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from HTTP/2 Node.js server!');
});
server.on('error', (err) => console.error(err));
server.listen(8443, () => {
console.log('HTTP/2 server listening on https://localhost:8443');
});
The http2.createSecureServer() method works similarly to https.createServer(), but it automatically handles the HTTP/2 protocol. The req and res objects are HTTP/2-specific stream objects, providing access to HTTP/2 features like stream IDs.
Using Server Push
Server push is a powerful feature where the server can send resources before the client explicitly requests them. This is typically used for critical assets like CSS or JavaScript files related to an HTML page.
const http2 = require('http2');
const fs = require('fs');
const path = require('path');
const options = {
key: fs.readFileSync('path/to/server.key'),
cert: fs.readFileSync('path/to/server.crt')
};
const server = http2.createSecureServer(options);
server.on('stream', (stream, headers) => {
const reqPath = headers[':path'];
if (reqPath === '/') {
// Push a CSS file along with the HTML
stream.pushStream({ ':path': '/style.css', ':method': 'GET' }, (pushStream) => {
pushStream.writeHead(200, { 'Content-Type': 'text/css' });
pushStream.end('body { background-color: lightblue; }');
});
stream.writeHead(200, { 'Content-Type': 'text/html' });
stream.end('<html><head><link rel="stylesheet" href="/style.css"></head><body><h1>Hello pushed CSS!</h1></body></html>');
} else if (reqPath === '/style.css') {
// If the client explicitly requests it (e.g., if push failed or wasn't used)
stream.writeHead(200, { 'Content-Type': 'text/css' });
stream.end('body { background-color: lightblue; }');
} else {
stream.writeHead(404);
stream.end('Not Found');
}
});
server.listen(8443, () => {
console.log('HTTP/2 server with push listening on https://localhost:8443');
});
Creating an HTTP/2 Client
You can also make HTTP/2 requests from Node.js using the http2.connect() method.
const http2 = require('http2');
const client = http2.connect('https://localhost:8443', {
// For self-signed certs, disable strict SSL verification for development
rejectUnauthorized: false
});
client.on('error', (err) => console.error(err));
const req = client.request({ ':method': 'GET', ':path': '/' });
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
console.log(`\n${data}`);
client.close();
});
req.end();
Important Considerations
- TLS Requirement: While HTTP/2 can technically run over plain TCP, all major browsers and many clients require HTTP/2 to be run over TLS (HTTPS). Always use
http2.createSecureServer()in production. - Performance Tuning: While HTTP/2 offers inherent performance benefits, proper implementation is still key. Overusing server push or pushing unneeded resources can degrade performance.
- Stream Management: Be mindful of stream limits and proper stream handling. Each request/response pair is a stream.
- Middleware Compatibility: Some existing HTTP/1.1 middleware might not be directly compatible with HTTP/2's stream-based API. You might need to adapt or use HTTP/2 specific libraries.
- HTTP/1.1 Fallback: Node.js
http2module supports ALPN (Application-Layer Protocol Negotiation) which allows clients to negotiate between HTTP/1.1 and HTTP/2 on the same port, defaulting to the highest supported protocol.
Node.js's robust http2 module makes it straightforward to leverage the performance advantages of HTTP/2, enabling developers to build faster and more efficient web applications.