Compatibility API
History
The Compatibility API has the goal of providing a similar developer experience of HTTP/1 when using HTTP/2, making it possible to develop applications that support both HTTP/1 and HTTP/2. This API targets only the public API of the HTTP/1. However many modules use internal methods or state, and those are not supported as it is a completely different implementation.
The following example creates an HTTP/2 server using the compatibility API:
import { createServer } from 'node:http2'; const server = createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8', 'X-Foo': 'bar', }); res.end('ok'); });
const http2 = require('node:http2'); const server = http2.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8', 'X-Foo': 'bar', }); res.end('ok'); });
In order to create a mixed HTTPS and HTTP/2 server, refer to the ALPN negotiation section. Upgrading from non-tls HTTP/1 servers is not supported.
The HTTP/2 compatibility API is composed of Http2ServerRequest and
Http2ServerResponse. They aim at API compatibility with HTTP/1, but
they do not hide the differences between the protocols. As an example,
the status message for HTTP codes is ignored.
ALPN negotiation allows supporting both HTTPS and HTTP/2 over
the same socket. The req and res objects can be either HTTP/1 or
HTTP/2, and an application must restrict itself to the public API of
HTTP/1, and detect if it is possible to use the more advanced
features of HTTP/2.
The following example creates a server that supports both protocols:
import { createSecureServer } from 'node:http2'; import { readFileSync } from 'node:fs'; const cert = readFileSync('./cert.pem'); const key = readFileSync('./key.pem'); const server = createSecureServer( { cert, key, allowHTTP1: true }, onRequest, ).listen(8000); function onRequest(req, res) { // Detects if it is an HTTPS request or HTTP/2 const { socket: { alpnProtocol } } = req.httpVersion === '2.0' ? req.stream.session : req; res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ alpnProtocol, httpVersion: req.httpVersion, })); }
const { createSecureServer } = require('node:http2'); const { readFileSync } = require('node:fs'); const cert = readFileSync('./cert.pem'); const key = readFileSync('./key.pem'); const server = createSecureServer( { cert, key, allowHTTP1: true }, onRequest, ).listen(4443); function onRequest(req, res) { // Detects if it is an HTTPS request or HTTP/2 const { socket: { alpnProtocol } } = req.httpVersion === '2.0' ? req.stream.session : req; res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ alpnProtocol, httpVersion: req.httpVersion, })); }
The 'request' event works identically on both HTTPS and
HTTP/2.
class http2.Http2ServerRequest extends stream.Readable
A Http2ServerRequest object is created by http2.Server or
http2.SecureServer and passed as the first argument to the
'request' event. It may be used to access a request status, headers, and
data.
The 'aborted' event is emitted whenever a Http2ServerRequest instance is
abnormally aborted in mid-communication.
The 'aborted' event will only be emitted if the Http2ServerRequest writable
side has not been ended.
Indicates that the underlying Http2Stream was closed.
Just like 'end', this event occurs only once per response.
booleanThe request.aborted property will be true if the request has
been aborted.
stringThe request authority pseudo header field. Because HTTP/2 allows requests
to set either :authority or host, this value is derived from
req.headers[':authority'] if present. Otherwise, it is derived from
req.headers['host'].
booleanThe request.complete property will be true if the request has
been completed, aborted, or destroyed.
request.socket.net.Socket | tls.TLSSocketSee request.socket.
request.destroy(error?): void
ErrorCalls destroy() on the Http2Stream that received
the Http2ServerRequest. If error is provided, an 'error' event
is emitted and error is passed as an argument to any listeners on the event.
It does nothing if the stream was already destroyed.
ObjectThe request/response headers object.
Key-value pairs of header names and values. Header names are lower-cased.
// Prints something like: // // { 'user-agent': 'curl/7.22.0', // host: '127.0.0.1:8000', // accept: '*/*' } console.log(request.headers);
In HTTP/2, the request path, host name, protocol, and method are represented as
special headers prefixed with the : character (e.g. ':path'). These special
headers will be included in the request.headers object. Care must be taken not
to inadvertently modify these special headers or errors may occur. For instance,
removing all headers from the request will cause errors to occur:
removeAllHeaders(request.headers); assert(request.url); // Fails because the :path header has been removed
stringIn case of server request, the HTTP version sent by the client. In the case of
client response, the HTTP version of the connected-to server. Returns
'2.0'.
Also message.httpVersionMajor is the first integer and
message.httpVersionMinor is the second.
stringThe request method as a string. Read-only. Examples: 'GET', 'DELETE'.
HTTP/2 Raw HeadersThe raw request/response headers list exactly as they were received.
// Prints something like: // // [ 'user-agent', // 'this is invalid because there can be only one', // 'User-Agent', // 'curl/7.22.0', // 'Host', // '127.0.0.1:8000', // 'ACCEPT', // '*/*' ] console.log(request.rawHeaders);
string[]The raw request/response trailer keys and values exactly as they were
received. Only populated at the 'end' event.
stringThe request scheme pseudo header field indicating the scheme portion of the target URL.
request.setTimeout(msecs, callback): http2.Http2ServerRequest
Sets the Http2Stream's timeout value to msecs. If a callback is
provided, then it is added as a listener on the 'timeout' event on
the response object.
If no 'timeout' listener is added to the request, the response, or
the server, then Http2Streams are destroyed when they time out. If a
handler is assigned to the request, the response, or the server's 'timeout'
events, timed out sockets must be handled explicitly.
net.Socket | tls.TLSSocketReturns a Proxy object that acts as a net.Socket (or tls.TLSSocket) but
applies getters, setters, and methods based on HTTP/2 logic.
destroyed, readable, and writable properties will be retrieved from and
set on request.stream.
destroy, emit, end, on and once methods will be called on
request.stream.
setTimeout method will be called on request.stream.session.
pause, read, resume, and write will throw an error with code
ERR_HTTP2_NO_SOCKET_MANIPULATION. See Http2Session and Sockets for
more information.
All other interactions will be routed directly to the socket. With TLS support,
use request.socket.getPeerCertificate() to obtain the client's
authentication details.
Http2StreamThe Http2Stream object backing the request.
ObjectThe request/response trailers object. Only populated at the 'end' event.
stringRequest URL string. This contains only the URL that is present in the actual HTTP request. If the request is:
GET /status?name=ryan HTTP/1.1 Accept: text/plain
Then request.url will be:
"/status?name=ryan"
To parse the url into its parts, new URL() can be used:
$ node > new URL('/status?name=ryan', 'http://example.com') URL { href: 'http://example.com/status?name=ryan', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/status', search: '?name=ryan', searchParams: URLSearchParams { 'name' => 'ryan' }, hash: '' }
class http2.Http2ServerResponse extends Stream
This object is created internally by an HTTP server, not by the user. It is
passed as the second parameter to the 'request' event.
Indicates that the underlying Http2Stream was terminated before
response.end() was called or able to flush.
Emitted when the response has been sent. More specifically, this event is emitted when the last segment of the response headers and body have been handed off to the HTTP/2 multiplexing for transmission over the network. It does not imply that the client has received anything yet.
After this event, no more events will be emitted on the response object.
response.addTrailers(headers): void
ObjectThis method adds HTTP trailing headers (a header but at the end of the message) to the response.
Attempting to set a header field name or value that contains invalid characters
will result in a TypeError being thrown.
response.appendHeader(name, value): void
Append a single header value to the header object.
If the value is an array, this is equivalent to calling this method multiple times.
If there were no previous values for the header, this is equivalent to calling
response.setHeader().
Attempting to set a header field name or value that contains invalid characters
will result in a TypeError being thrown.
// Returns headers including "set-cookie: a" and "set-cookie: b" const server = http2.createServer((req, res) => { res.setHeader('set-cookie', 'a'); res.appendHeader('set-cookie', 'b'); res.writeHead(200); res.end('ok'); });
response.socket.net.Socket | tls.TLSSocketSee response.socket.
response.createPushResponse(headers, callback): void
HTTP/2 Headers ObjectFunctionhttp2stream.pushStream() is finished,
or either when the attempt to create the pushed Http2Stream has failed or
has been rejected, or the state of Http2ServerRequest is closed prior to
calling the http2stream.pushStream() methodErrorHttp2ServerResponse
objectCall http2stream.pushStream() with the given headers, and wrap the
given Http2Stream on a newly created Http2ServerResponse as the callback
parameter if successful. When Http2ServerRequest is closed, the callback is
called with an error ERR_HTTP2_INVALID_STREAM.
response.end
History
ServerResponse.response.end(data?, encoding?, callback?): this
This method signals to the server that all of the response headers and body
have been sent; that server should consider this message complete.
The method, response.end(), MUST be called on each response.
If data is specified, it is equivalent to calling
response.write(data, encoding) followed by response.end(callback).
If callback is specified, it will be called when the response stream
is finished.
response.writableEnded.booleanBoolean value that indicates whether the response has completed. Starts
as false. After response.end() executes, the value will be true.
response.getHeader(name): string
Reads out a header that has already been queued but not sent to the client. The name is case-insensitive.
const contentType = response.getHeader('content-type');
response.getHeaderNames(): string[]
string[]Returns an array containing the unique names of the current outgoing headers. All header names are lowercase.
response.setHeader('Foo', 'bar'); response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); const headerNames = response.getHeaderNames(); // headerNames === ['foo', 'set-cookie']
response.getHeaders(): Object
ObjectReturns a shallow copy of the current outgoing headers. Since a shallow copy is used, array values may be mutated without additional calls to various header-related http module methods. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.
The object returned by the response.getHeaders() method does not
prototypically inherit from the JavaScript Object. This means that typical
Object methods such as obj.toString(), obj.hasOwnProperty(), and others
are not defined and will not work.
response.setHeader('Foo', 'bar'); response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); const headers = response.getHeaders(); // headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] }
response.hasHeader(name): boolean
Returns true if the header identified by name is currently set in the
outgoing headers. The header name matching is case-insensitive.
const hasContentType = response.hasHeader('content-type');
booleanTrue if headers were sent, false otherwise (read-only).
response.removeHeader(name): void
stringRemoves a header that has been queued for implicit sending.
response.removeHeader('Content-Encoding');
A reference to the original HTTP2 request object.
booleanWhen true, the Date header will be automatically generated and sent in the response if it is not already present in the headers. Defaults to true.
This should only be disabled for testing; HTTP requires the Date header in responses.
response.setHeader(name, value): void
Sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here to send multiple headers with the same name.
response.setHeader('Content-Type', 'text/html; charset=utf-8');
or
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
Attempting to set a header field name or value that contains invalid characters
will result in a TypeError being thrown.
When headers have been set with response.setHeader(), they will be merged
with any headers passed to response.writeHead(), with the headers passed
to response.writeHead() given precedence.
// Returns content-type = text/plain const server = http2.createServer((req, res) => { res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.setHeader('X-Foo', 'bar'); res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('ok'); });
response.setTimeout(msecs, callback?): http2.Http2ServerResponse
Sets the Http2Stream's timeout value to msecs. If a callback is
provided, then it is added as a listener on the 'timeout' event on
the response object.
If no 'timeout' listener is added to the request, the response, or
the server, then Http2Streams are destroyed when they time out. If a
handler is assigned to the request, the response, or the server's 'timeout'
events, timed out sockets must be handled explicitly.
net.Socket | tls.TLSSocketReturns a Proxy object that acts as a net.Socket (or tls.TLSSocket) but
applies getters, setters, and methods based on HTTP/2 logic.
destroyed, readable, and writable properties will be retrieved from and
set on response.stream.
destroy, emit, end, on and once methods will be called on
response.stream.
setTimeout method will be called on response.stream.session.
pause, read, resume, and write will throw an error with code
ERR_HTTP2_NO_SOCKET_MANIPULATION. See Http2Session and Sockets for
more information.
All other interactions will be routed directly to the socket.
import { createServer } from 'node:http2'; const server = createServer((req, res) => { const ip = req.socket.remoteAddress; const port = req.socket.remotePort; res.end(`Your IP address is ${ip} and your source port is ${port}.`); }).listen(3000);
const http2 = require('node:http2'); const server = http2.createServer((req, res) => { const ip = req.socket.remoteAddress; const port = req.socket.remotePort; res.end(`Your IP address is ${ip} and your source port is ${port}.`); }).listen(3000);
numberWhen using implicit headers (not calling response.writeHead() explicitly),
this property controls the status code that will be sent to the client when
the headers get flushed.
response.statusCode = 404;
After response header was sent to the client, this property indicates the status code which was sent out.
stringStatus message is not supported by HTTP/2 (RFC 7540 8.1.2.4). It returns an empty string.
Http2StreamThe Http2Stream object backing the response.
booleanIs true after response.end() has been called. This property
does not indicate whether the data has been flushed, for this use
writable.writableFinished instead.
response.write(chunk, encoding?, callback?): boolean
If this method is called and response.writeHead() has not been called,
it will switch to implicit header mode and flush the implicit headers.
This sends a chunk of the response body. This method may be called multiple times to provide successive parts of the body.
In the node:http module, the response body is omitted when the
request is a HEAD request. Similarly, the 204 and 304 responses
must not include a message body.
chunk can be a string or a buffer. If chunk is a string,
the second parameter specifies how to encode it into a byte stream.
By default the encoding is 'utf8'. callback will be called when this chunk
of data is flushed.
This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used.
The first time response.write() is called, it will send the buffered
header information and the first chunk of the body to the client. The second
time response.write() is called, Node.js assumes data will be streamed,
and sends the new data separately. That is, the response is buffered up to the
first chunk of the body.
Returns true if the entire data was flushed successfully to the kernel
buffer. Returns false if all or part of the data was queued in user memory.
'drain' will be emitted when the buffer is free again.
response.writeContinue(): void
Sends a status 100 Continue to the client, indicating that the request body
should be sent. See the 'checkContinue' event on Http2Server and
Http2SecureServer.
response.writeEarlyHints(hints): void
ObjectSends a status 103 Early Hints to the client with a Link header,
indicating that the user agent can preload/preconnect the linked resources.
The hints is an object containing the values of headers to be sent with
early hints message.
Example
const earlyHintsLink = '</styles.css>; rel=preload; as=style'; response.writeEarlyHints({ 'link': earlyHintsLink, }); const earlyHintsLinks = [ '</styles.css>; rel=preload; as=style', '</scripts.js>; rel=preload; as=script', ]; response.writeEarlyHints({ 'link': earlyHintsLinks, });
response.writeInformation(statusCode, headers?): void
Sends an arbitrary HTTP 1xx informational response, equivalent in HTTP/2 to a
HEADERS frame whose :status pseudo-header is a 1xx code. May be called
multiple times before the final response. After the final response headers
have been sent, this method is a no-op and returns false.
This is the generic equivalent of response.writeContinue() and
response.writeEarlyHints().
response.writeInformation(110, { 'X-Progress': '50%' });
response.writeHead
History
this from writeHead() to allow chaining with end().response.writeHead(statusCode, statusMessage?, headers?): http2.Http2ServerResponse
numberstringHTTP/2 Headers Object | HTTP/2 Raw Headershttp2.Http2ServerResponseSends a response header to the request. The status code is a 3-digit HTTP
status code, like 404. The last argument, headers, are the response headers.
Returns a reference to the Http2ServerResponse, so that calls can be chained.
For compatibility with HTTP/1, a human-readable statusMessage may be
passed as the second argument. However, because the statusMessage has no
meaning within HTTP/2, the argument will have no effect and a process warning
will be emitted.
const body = 'hello world'; response.writeHead(200, { 'Content-Length': Buffer.byteLength(body), 'Content-Type': 'text/plain; charset=utf-8', });
Content-Length is given in bytes not characters. The
Buffer.byteLength() API may be used to determine the number of bytes in a
given encoding. On outbound messages, Node.js does not check if Content-Length
and the length of the body being transmitted are equal or not. However, when
receiving messages, Node.js will automatically reject messages when the
Content-Length does not match the actual payload size.
This method may be called at most one time on a message before
response.end() is called.
If response.write() or response.end() are called before calling
this, the implicit/mutable headers will be calculated and call this function.
When headers have been set with response.setHeader(), they will be merged
with any headers passed to response.writeHead(), with the headers passed
to response.writeHead() given precedence.
// Returns content-type = text/plain const server = http2.createServer((req, res) => { res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.setHeader('X-Foo', 'bar'); res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('ok'); });
Attempting to set a header field name or value that contains invalid characters
will result in a TypeError being thrown.