Skip to content

Commit 5840a7e

Browse files
committed
add node:http and node:https documentation
address pr reviews address pr reviews
1 parent b13ce04 commit 5840a7e

File tree

3 files changed

+355
-102
lines changed

3 files changed

+355
-102
lines changed

src/content/docs/workers/runtime-apis/nodejs/http.mdx

Lines changed: 232 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,50 @@ pcx_content_type: configuration
33
title: http
44
---
55

6-
import { Render } from "~/components"
6+
import { Render } from "~/components";
77

88
<Render file="nodejs-compat-howto" />
99

10+
## Compatibility flags
11+
12+
### Client-side methods
13+
14+
To use the HTTP client-side methods (`http.get`, `http.request`, etc.), you must enable the [`enable_nodejs_http_modules`](/workers/configuration/compatibility-flags/) compatibility flag in addition to the [`nodejs_compat`](/workers/runtime-apis/nodejs/) flag.
15+
16+
This flag is automatically enabled for Workers using a [compatibility date](/workers/configuration/compatibility-dates/) of `2025-08-15` or later when `nodejs_compat` is enabled. For Workers using an earlier compatibility date, you can manually enable it by adding the flag to your `wrangler.toml`:
17+
18+
```toml
19+
compatibility_flags = ["nodejs_compat", "enable_nodejs_http_modules"]
20+
```
21+
22+
### Server-side methods
23+
24+
To use the HTTP server-side methods (`http.createServer`, `http.Server`, `http.ServerResponse`), you must enable the `enable_nodejs_http_server_modules` compatibility flag in addition to the [`nodejs_compat`](/workers/runtime-apis/nodejs/) flag.
25+
26+
This flag is automatically enabled for Workers using a [compatibility date](/workers/configuration/compatibility-dates/) of `2025-09-01` or later when `nodejs_compat` is enabled. For Workers using an earlier compatibility date, you can manually enable it by adding the flag to your `wrangler.toml`:
27+
28+
```toml
29+
compatibility_flags = ["nodejs_compat", "enable_nodejs_http_server_modules"]
30+
```
31+
32+
To use both client-side and server-side methods, enable both flags:
33+
34+
```toml
35+
compatibility_flags = ["nodejs_compat", "enable_nodejs_http_modules", "enable_nodejs_http_server_modules"]
36+
```
37+
1038
## Agent
1139

12-
An implementation of the Node.js [`http.Agent'](https://nodejs.org/docs/latest/api/http.html#class-httpagent) class.
40+
An implementation of the Node.js [`http.Agent`](https://nodejs.org/docs/latest/api/http.html#class-httpagent) class.
1341

14-
An [Agent](https://nodejs.org/docs/latest/api/http.html#class-httpagent) manages HTTP connection reuse by maintaining request queues per host/port. In the
15-
workers environment, however, such low-level management of the network connection, ports,
16-
etc, is not relevant because it is handled by the Cloudflare infrastructure instead. Accordingly, the
17-
implementation of `Agent` in Workers is a stub implementation that does not support connection
18-
pooling or keep-alive.
42+
An [Agent](https://nodejs.org/docs/latest/api/http.html#class-httpagent) manages HTTP connection reuse by maintaining request queues per host/port. In the Workers environment, however, such low-level management of the network connection, ports, etc, is not relevant because it is handled by the Cloudflare infrastructure instead. Accordingly, the implementation of `Agent` in Workers is a stub implementation that does not support connection pooling or keep-alive.
1943

2044
```js
21-
import { Agent } from 'node:http';
22-
import { strictEqual } from 'node:assert';
45+
import { Agent } from "node:http";
46+
import { strictEqual } from "node:assert";
2347

2448
const agent = new Agent();
25-
strictEqual(agent.protocol, 'http:');
49+
strictEqual(agent.protocol, "http:");
2650
```
2751

2852
## get
@@ -32,66 +56,75 @@ An implementation of the Node.js [`http.get`](https://nodejs.org/docs/latest/api
3256
The `get` method performs a GET request to the specified URL and invokes the callback with the response. It's a convenience method that simplifies making HTTP GET requests without manually configuring request options.
3357

3458
```js
35-
import { get } from 'node:http';
36-
import { strictEqual, ok } from 'node:assert';
37-
38-
get('http://docs.cloudflare.com/robots.txt', (res) => {
39-
// requests to http://docs.cloudflare.com get redirected to their https counterpart.
40-
strictEqual(res.statusCode, 301);
41-
let data = '';
42-
res.setEncoding('utf8');
43-
res.on('data', (chunk) => {
44-
data += chunk;
45-
});
46-
res.on('end', () => {
47-
ok(data.includes('301 Moved Permanently'));
48-
});
49-
});
59+
import { get } from "node:http";
60+
import { strictEqual, ok } from "node:assert";
61+
62+
export default {
63+
async fetch() {
64+
const { promise, resolve, reject } = Promise.withResolvers();
65+
get("http://docs.cloudflare.com/robots.txt", (res) => {
66+
// requests to http://docs.cloudflare.com get redirected to their https counterpart.
67+
strictEqual(res.statusCode, 301);
68+
let data = "";
69+
res.setEncoding("utf8");
70+
res.on("data", (chunk) => {
71+
data += chunk;
72+
});
73+
res.once("error", reject);
74+
res.on("end", () => {
75+
ok(data.includes("301 Moved Permanently"));
76+
resolve(new Response(data));
77+
});
78+
});
79+
return promise;
80+
},
81+
};
5082
```
5183

5284
## request
5385

54-
An implementation of the Node.js [`http.request'](https://nodejs.org/docs/latest/api/http.html#httprequesturl-options-callback) method.
86+
An implementation of the Node.js [`http.request`](https://nodejs.org/docs/latest/api/http.html#httprequesturl-options-callback) method.
5587

5688
The `request` method creates an HTTP request with customizable options like method, headers, and body. It provides full control over the request configuration and returns a [writable stream](https://nodejs.org/docs/latest/api/stream.html#class-streamwritable) for sending request data.
5789

5890
```js
59-
import { request } from 'node:http';
60-
import { strictEqual } from 'node:assert';
61-
62-
const req = request({
63-
method: 'GET',
64-
protocol: 'http:',
65-
hostname: 'docs.cloudflare.com',
66-
path: '/'
67-
}, (res) => {
68-
// requests to http://docs.cloudflare.com get redirected to their https counterpart.
69-
strictEqual(res.statusCode, 301);
70-
71-
let data = '';
72-
res.setEncoding('utf8');
73-
res.on('data', (chunk) => {
74-
data += chunk;
75-
});
76-
res.on('end', () => {
77-
ok(data.includes('301 Moved Permanently'));
78-
});
79-
});
80-
req.end();
81-
```
91+
import { request } from "node:http";
92+
import { strictEqual, ok } from "node:assert";
8293

83-
```js
84-
const req = request(new URL('http://docs.cloudflare.com'),{
85-
method: 'GET',
86-
}, (res) => {
87-
// requests to http://docs.cloudflare.com get redirected to their https counterpart.
88-
strictEqual(res.statusCode, 301);
89-
});
94+
export default {
95+
async fetch() {
96+
const { promise, resolve, reject } = Promise.withResolvers();
97+
const req = request(
98+
{
99+
method: "GET",
100+
protocol: "http:",
101+
hostname: "docs.cloudflare.com",
102+
path: "/",
103+
},
104+
(res) => {
105+
// requests to http://docs.cloudflare.com get redirected to their https counterpart.
106+
strictEqual(res.statusCode, 301);
90107

91-
req.end();
108+
let data = "";
109+
res.setEncoding("utf8");
110+
res.on("data", (chunk) => {
111+
data += chunk;
112+
});
113+
res.once("error", reject);
114+
res.on("end", () => {
115+
ok(data.includes("301 Moved Permanently"));
116+
resolve(new Response(data));
117+
});
118+
},
119+
);
120+
req.end();
121+
return promise;
122+
},
123+
};
92124
```
93125

94-
The following options passed to the `request` method are not supported due to the differences in the Cloudflare Workers and the implementation of the `node:http` module:
126+
The following options passed to the `request` method are not supported due to differences in the Cloudflare Workers implementation of the `node:http` module:
127+
95128
- `maxHeaderSize`
96129
- `insecureHTTPParser`
97130
- `createConnection`
@@ -100,26 +133,154 @@ The following options passed to the `request` method are not supported due to th
100133

101134
## OutgoingMessage
102135

103-
The [`OutgoingMessage`](https://nodejs.org/docs/latest/api/http.html#class-httpoutgoingmessage) class represents an HTTP response that is sent to the client. It provides methods for writing response headers and body, as well as for ending the response. `OutgoingMessage` extends from the [`Writable` stream class](https://nodejs.org/docs/latest/api/stream.html#class-streamwritable).
136+
An implementation of the Node.js [`http.OutgoingMessage`](https://nodejs.org/docs/latest/api/http.html#class-httpoutgoingmessage) class.
137+
138+
The `OutgoingMessage` class is a base class for outgoing HTTP messages (both requests and responses). It provides methods for writing headers and body data, as well as for ending the message. `OutgoingMessage` extends from the [`Writable` stream class](https://nodejs.org/docs/latest/api/stream.html#class-streamwritable).
139+
140+
Both `ClientRequest` and `ServerResponse` both extend from and inherit from `OutgoingMessage`.
141+
142+
## IncomingMessage
143+
144+
An implementation of the Node.js [`http.IncomingMessage`](https://nodejs.org/docs/latest/api/http.html#class-httpincomingmessage) class.
145+
146+
The `IncomingMessage` class represents an HTTP message (request or response). It provides methods for reading headers and body data. `IncomingMessage` extends from the `Readable` stream class.
104147

105148
```js
106-
import { OutgoingMessage } from 'node:http';
149+
import { get, IncomingMessage } from "node:http";
150+
import { ok, strictEqual } from "node:assert";
107151

108-
const res = new OutgoingMessage();
109-
res.writeHead(200, { 'Content-Type': 'text/plain' });
110-
res.write('Hello, World!');
111-
res.end();
152+
export default {
153+
async fetch() {
154+
const { promise, resolve } = Promise.withResolvers();
155+
get("http://docs.cloudflare.com", (res) => {
156+
strictEqual(res.statusCode, 301);
157+
ok(res instanceof IncomingMessage);
158+
resolve(new Response("ok"));
159+
});
160+
return promise;
161+
},
162+
};
112163
```
113-
## IncomingMessage
114164

115-
The `IncomingMessage` class represents an HTTP request that is received from the client. It provides methods for reading request headers and body, as well as for ending the request. `IncomingMessage` extends from the `Readable` stream class.
165+
The Workers implementation includes a `cloudflare` property on `IncomingMessage` objects:
116166

117167
```js
118-
import { get, IncomingMessage } from 'node:http';
119-
import { ok, strictEqual } from 'node:assert';
168+
import { createServer } from "node:http";
169+
import { httpServerHandler } from "cloudflare:node";
120170

121-
get('http://docs.cloudflare.com', (res) => {
122-
strictEqual(res.statusCode, 301);
123-
ok(res instanceof IncomingMessage);
171+
const server = createServer((req, res) => {
172+
console.log(res.cloudflare.cf.country);
173+
console.log(res.cloudflare.cf.ray);
174+
res.write("Hello, World!");
175+
res.end();
124176
});
177+
178+
server.listen(8080);
179+
180+
export default httpServerHandler({ port: 8080 });
125181
```
182+
183+
The `cloudflare.cf` property contains [Cloudflare-specific request properties](/workers/runtime-apis/request/#incomingrequestcfproperties).
184+
185+
The following differences exist between the Workers implementation and Node.js:
186+
187+
- Trailer headers are not supported
188+
- The `socket` attribute **does not extend from `net.Socket`** and only contains the following properties: `encrypted`, `remoteFamily`, `remoteAddress`, `remotePort`, `localAddress`, `localPort`, and `destroy()` method.
189+
- The following `socket` attributes behave differently than their Node.js counterparts:
190+
- `remoteAddress` will return `127.0.0.1` when ran locally
191+
- `remotePort` will return a random port number between 2^15 and 2^16
192+
- `localAddress` will return the value of request's `host` header if exists. Otherwise, it will return `127.0.0.1`
193+
- `localPort` will return the port number assigned to the server instance
194+
- `req.socket.destroy()` falls through to `req.destroy()`
195+
196+
## createServer
197+
198+
An implementation of the Node.js [`http.createServer`](https://nodejs.org/docs/latest/api/http.html#httpcreateserveroptions-requestlistener) method.
199+
200+
The `createServer` method creates an HTTP server instance that can handle incoming requests.
201+
202+
```js
203+
import { createServer } from "node:http";
204+
import { httpServerHandler } from "cloudflare:node";
205+
206+
const server = createServer((req, res) => {
207+
res.writeHead(200, { "Content-Type": "text/plain" });
208+
res.end("Hello from Node.js HTTP server!");
209+
});
210+
211+
server.listen(8080);
212+
export default httpServerHandler({ port: 8080 });
213+
```
214+
215+
The `httpServerHandler` function integrates Node.js HTTP servers with the Cloudflare Workers request model. When a request arrives at your Worker, the handler automatically routes it to your Node.js server running on the specified port. Handler is using the specified port to determine which app to route the request to. This bridge allows you to use familiar Node.js server patterns while benefiting from the Workers runtime environment, including automatic scaling, edge deployment, and integration with other Cloudflare services.
216+
217+
:::note
218+
Failing to call `close()` on an HTTP server may result in the server persisting until the worker is destroyed. In most cases, this is not an issue since servers typically live for the lifetime of the worker. However, if you need to create multiple servers during a worker's lifetime or want explicit lifecycle control (such as in test scenarios), call `close()` when you're done with the server, or use [explicit resource management](https://v8.dev/features/explicit-resource-management).
219+
:::
220+
221+
## Server
222+
223+
An implementation of the Node.js [`http.Server`](https://nodejs.org/docs/latest/api/http.html#class-httpserver) class.
224+
225+
The `Server` class represents an HTTP server and provides methods for handling incoming requests. It extends the Node.js `EventEmitter` class and can be used to create custom server implementations.
226+
227+
When using `httpServerHandler`, the port number specified in `server.listen()` acts as a routing key rather than an actual network port. The handler uses this port to determine which HTTP server instance should handle incoming requests, allowing multiple servers to coexist within the same Worker by using different port numbers for identification. Using a port value of `0` (or `null` or `undefined`) will result in a random port number being assigned.
228+
229+
```js
230+
import { Server } from "node:http";
231+
import { httpServerHandler } from "cloudflare:node";
232+
233+
const server = new Server((req, res) => {
234+
res.writeHead(200, { "Content-Type": "application/json" });
235+
res.end(JSON.stringify({ message: "Hello from HTTP Server!" }));
236+
});
237+
238+
server.listen(8080);
239+
export default httpServerHandler({ port: 8080 });
240+
```
241+
242+
The following differences exist between the Workers implementation and Node.js:
243+
244+
- Connection management methods such as `closeAllConnections()` and `closeIdleConnections()` are not implemented
245+
- Only `listen()` variants with a port number or no parameters are supported: `listen()`, `listen(0, callback)`, `listen(callback)`, etc. For reference, see the [Node.js documentation](https://nodejs.org/docs/latest/api/net.html#serverlisten).
246+
- The following server options are not supported: `maxHeaderSize`, `insecureHTTPParser`, `keepAliveTimeout`, `connectionsCheckingInterval`
247+
248+
## ServerResponse
249+
250+
An implementation of the Node.js [`http.ServerResponse`](https://nodejs.org/docs/latest/api/http.html#class-httpserverresponse) class.
251+
252+
The `ServerResponse` class represents the server-side response object that is passed to request handlers. It provides methods for writing response headers and body data, and extends the Node.js `Writable` stream class.
253+
254+
```js
255+
import { createServer } from "node:http";
256+
import { httpServerHandler } from "cloudflare:node";
257+
258+
const server = createServer((req, res) => {
259+
ok(res instanceof ServerResponse);
260+
261+
// Set multiple headers at once
262+
res.writeHead(200, {
263+
"Content-Type": "application/json",
264+
"X-Custom-Header": "Workers-HTTP",
265+
});
266+
267+
// Stream response data
268+
res.write('{"data": [');
269+
res.write('{"id": 1, "name": "Item 1"},');
270+
res.write('{"id": 2, "name": "Item 2"}');
271+
res.write("]}");
272+
273+
// End the response
274+
res.end();
275+
});
276+
277+
server.listen(8080);
278+
export default httpServerHandler({ port: 8080 });
279+
```
280+
281+
The following methods and features are not supported in the Workers implementation:
282+
283+
- `assignSocket()` and `detachSocket()` methods are not available
284+
- Trailer headers are not supported
285+
- `writeContinue()` and `writeEarlyHints()` methods are not available
286+
- 1xx responses in general are not supported

0 commit comments

Comments
 (0)