Skip to content

Commit 3a31ac0

Browse files
authored
Improve and extend node:http docs (#23808)
* Improve Agent example, move to end Move the `Agent` part of the docs to the end since it's only a stub impl and really isn't all that useful. Also improve the example to show how one might actually use it. * Improve and expand node:http docs, examples
1 parent a67cf60 commit 3a31ac0

File tree

2 files changed

+215
-127
lines changed

2 files changed

+215
-127
lines changed

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

Lines changed: 123 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -7,91 +7,86 @@ import { Render } from "~/components"
77

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

10-
## Agent
11-
12-
An implementation of the Node.js [`http.Agent'](https://nodejs.org/docs/latest/api/http.html#class-httpagent) class.
13-
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.
19-
20-
```js
21-
import { Agent } from 'node:http';
22-
import { strictEqual } from 'node:assert';
23-
24-
const agent = new Agent();
25-
strictEqual(agent.protocol, 'http:');
26-
```
27-
2810
## get
2911

3012
An implementation of the Node.js [`http.get`](https://nodejs.org/docs/latest/api/http.html#httpgetoptions-callback) method.
3113

3214
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.
3315

16+
Because `get` is a wrapper around `fetch(...)`, it may be used only within an exported
17+
fetch or similar handler. Outside of such a handler, attempts to use `get` will throw
18+
an error.
19+
3420
```js
3521
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-
});
22+
23+
export default {
24+
async fetch() {
25+
const { promise, resolve, reject } = Promise.withResolvers();
26+
get('http://example.org', (res) => {
27+
let data = '';
28+
res.setEncoding('utf8');
29+
res.on('data', (chunk) => {
30+
data += chunk;
31+
});
32+
res.on('end', () => {
33+
resolve(new Response(data));
34+
});
35+
res.on('error', reject);
36+
}).on('error', reject);
37+
return promise;
38+
}
39+
}
5040
```
5141

42+
The implementation of `get` in Workers is a wrapper around the global
43+
[`fetch` API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
44+
and is therefore subject to the same [limits](https://developers.cloudflare.com/workers/platform/limits/).
45+
46+
As shown in the example above, it is necessary to arrange for requests to be correctly
47+
awaited in the `fetch` handler using a promise or the fetch may be canceled prematurely
48+
when the handler returns.
49+
5250
## request
5351

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

56-
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.
54+
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 Node.js [stream.Writable](https://developers.cloudflare.com/workers/runtime-apis/nodejs/streams/) for sending request data.
55+
56+
Because `request` is a wrapper around `fetch(...)`, it may be used only within an exported
57+
fetch or similar handler. Outside of such a handler, attempts to use `request` will throw
58+
an error.
5759

5860
```js
59-
import { request } from 'node:http';
60-
import { strictEqual } from 'node:assert';
61+
import { get } from 'node:http';
6162

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();
63+
export default {
64+
async fetch() {
65+
const { promise, resolve, reject } = Promise.withResolvers();
66+
get({
67+
method: 'GET',
68+
protocol: 'http:',
69+
hostname: 'example.org',
70+
path: '/'
71+
}, (res) => {
72+
let data = '';
73+
res.setEncoding('utf8');
74+
res.on('data', (chunk) => {
75+
data += chunk;
76+
});
77+
res.on('end', () => {
78+
resolve(new Response(data));
79+
});
80+
res.on('error', reject);
81+
}).on('error', reject)
82+
.end();
83+
return promise;
84+
}
85+
}
8186
```
8287

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-
});
90-
91-
req.end();
92-
```
88+
The following options passed to the `request` (and `get`) method are not supported due to the differences required by Coudflare Workers implementation of `node:http` as a wrapper around the global `fetch` API:
9389

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:
9590
- `maxHeaderSize`
9691
- `insecureHTTPParser`
9792
- `createConnection`
@@ -100,16 +95,23 @@ The following options passed to the `request` method are not supported due to th
10095

10196
## OutgoingMessage
10297

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).
98+
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 Node.js [`stream.Writable` stream class](https://developers.cloudflare.com/workers/runtime-apis/nodejs/streams/).
10499

105100
```js
106101
import { OutgoingMessage } from 'node:http';
107102

108-
const res = new OutgoingMessage();
109-
res.writeHead(200, { 'Content-Type': 'text/plain' });
110-
res.write('Hello, World!');
111-
res.end();
103+
export default {
104+
async fetch() {
105+
// ...
106+
const res = new OutgoingMessage();
107+
res.writeHead(200, { 'Content-Type': 'text/plain' });
108+
res.write('Hello, World!');
109+
res.end();
110+
// ...
111+
}
112+
}
112113
```
114+
113115
## IncomingMessage
114116

115117
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.
@@ -118,8 +120,55 @@ The `IncomingMessage` class represents an HTTP request that is received from the
118120
import { get, IncomingMessage } from 'node:http';
119121
import { ok, strictEqual } from 'node:assert';
120122

121-
get('http://docs.cloudflare.com', (res) => {
122-
strictEqual(res.statusCode, 301);
123-
ok(res instanceof IncomingMessage);
124-
});
123+
export default {
124+
async fetch() {
125+
// ...
126+
get('http://example.org', (res) => {
127+
ok(res instanceof IncomingMessage);
128+
});
129+
// ...
130+
}
131+
}
125132
```
133+
134+
## Agent
135+
136+
A partial implementation of the Node.js [`http.Agent'](https://nodejs.org/docs/latest/api/http.html#class-httpagent) class.
137+
138+
An `Agent` 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.
139+
140+
```js
141+
import { get, Agent } from 'node:http';
142+
import { strictEqual } from 'node:assert';
143+
144+
export default {
145+
async fetch() {
146+
147+
const agent = new Agent();
148+
get({
149+
hostname: 'example.org',
150+
port: 80,
151+
path: '/',
152+
agent, // possible but not all that useful.
153+
}, (res) => {
154+
// ...
155+
});
156+
157+
return new Response('ok');
158+
}
159+
}
160+
```
161+
162+
## Other differences between Node.js and Workers implementation of `node:http`
163+
164+
Because the Workers implementation of `node:http` is a wrapper around the global `fetch` API, there are some differences in behavior and limitations compared to a standard Node.js environment:
165+
166+
* `Connection` headers are not used. Workers will manage connections automatically.
167+
* `Content-Length` headers will be handled the same way as in the `fetch` API. If a body is provided, the header will be set automatically and manually set values will be ignored.
168+
* `Expect: 100-continue` headers are not supported.
169+
* Trailing headers are not supported.
170+
* The `'continue'` event is not supported.
171+
* The `'information'` event is not supported.
172+
* The `'socket'` event is not supported.
173+
* The `'upgrade'` event is not supported.
174+
* Gaining direct access to the underlying `socket` is not supported.

0 commit comments

Comments
 (0)