source: node_modules/undici/docs/api/Dispatcher.md

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 26.9 KB
Line 
1# Dispatcher
2
3Extends: `events.EventEmitter`
4
5Dispatcher is the core API used to dispatch requests.
6
7Requests are not guaranteed to be dispatched in order of invocation.
8
9## Instance Methods
10
11### `Dispatcher.close([callback]): Promise`
12
13Closes the dispatcher and gracefully waits for enqueued requests to complete before resolving.
14
15Arguments:
16
17* **callback** `(error: Error | null, data: null) => void` (optional)
18
19Returns: `void | Promise<null>` - Only returns a `Promise` if no `callback` argument was passed
20
21```js
22dispatcher.close() // -> Promise
23dispatcher.close(() => {}) // -> void
24```
25
26#### Example - Request resolves before Client closes
27
28```js
29import { createServer } from 'http'
30import { Client } from 'undici'
31import { once } from 'events'
32
33const server = createServer((request, response) => {
34 response.end('undici')
35}).listen()
36
37await once(server, 'listening')
38
39const client = new Client(`http://localhost:${server.address().port}`)
40
41try {
42 const { body } = await client.request({
43 path: '/',
44 method: 'GET'
45 })
46 body.setEncoding('utf8')
47 body.on('data', console.log)
48} catch (error) {}
49
50await client.close()
51
52console.log('Client closed')
53server.close()
54```
55
56### `Dispatcher.connect(options[, callback])`
57
58Starts two-way communications with the requested resource using [HTTP CONNECT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT).
59
60Arguments:
61
62* **options** `ConnectOptions`
63* **callback** `(err: Error | null, data: ConnectData | null) => void` (optional)
64
65Returns: `void | Promise<ConnectData>` - Only returns a `Promise` if no `callback` argument was passed
66
67#### Parameter: `ConnectOptions`
68
69* **path** `string`
70* **headers** `UndiciHeaders` (optional) - Default: `null`
71* **signal** `AbortSignal | events.EventEmitter | null` (optional) - Default: `null`
72* **opaque** `unknown` (optional) - This argument parameter is passed through to `ConnectData`
73
74#### Parameter: `ConnectData`
75
76* **statusCode** `number`
77* **headers** `Record<string, string | string[] | undefined>`
78* **socket** `stream.Duplex`
79* **opaque** `unknown`
80
81#### Example - Connect request with echo
82
83```js
84import { createServer } from 'http'
85import { Client } from 'undici'
86import { once } from 'events'
87
88const server = createServer((request, response) => {
89 throw Error('should never get here')
90}).listen()
91
92server.on('connect', (req, socket, head) => {
93 socket.write('HTTP/1.1 200 Connection established\r\n\r\n')
94
95 let data = head.toString()
96 socket.on('data', (buf) => {
97 data += buf.toString()
98 })
99
100 socket.on('end', () => {
101 socket.end(data)
102 })
103})
104
105await once(server, 'listening')
106
107const client = new Client(`http://localhost:${server.address().port}`)
108
109try {
110 const { socket } = await client.connect({
111 path: '/'
112 })
113 const wanted = 'Body'
114 let data = ''
115 socket.on('data', d => { data += d })
116 socket.on('end', () => {
117 console.log(`Data received: ${data.toString()} | Data wanted: ${wanted}`)
118 client.close()
119 server.close()
120 })
121 socket.write(wanted)
122 socket.end()
123} catch (error) { }
124```
125
126### `Dispatcher.destroy([error, callback]): Promise`
127
128Destroy the dispatcher abruptly with the given error. All the pending and running requests will be asynchronously aborted and error. Since this operation is asynchronously dispatched there might still be some progress on dispatched requests.
129
130Both arguments are optional; the method can be called in four different ways:
131
132Arguments:
133
134* **error** `Error | null` (optional)
135* **callback** `(error: Error | null, data: null) => void` (optional)
136
137Returns: `void | Promise<void>` - Only returns a `Promise` if no `callback` argument was passed
138
139```js
140dispatcher.destroy() // -> Promise
141dispatcher.destroy(new Error()) // -> Promise
142dispatcher.destroy(() => {}) // -> void
143dispatcher.destroy(new Error(), () => {}) // -> void
144```
145
146#### Example - Request is aborted when Client is destroyed
147
148```js
149import { createServer } from 'http'
150import { Client } from 'undici'
151import { once } from 'events'
152
153const server = createServer((request, response) => {
154 response.end()
155}).listen()
156
157await once(server, 'listening')
158
159const client = new Client(`http://localhost:${server.address().port}`)
160
161try {
162 const request = client.request({
163 path: '/',
164 method: 'GET'
165 })
166 client.destroy()
167 .then(() => {
168 console.log('Client destroyed')
169 server.close()
170 })
171 await request
172} catch (error) {
173 console.error(error)
174}
175```
176
177### `Dispatcher.dispatch(options, handler)`
178
179This is the low level API which all the preceding APIs are implemented on top of.
180This API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs.
181It is primarily intended for library developers who implement higher level APIs on top of this.
182
183Arguments:
184
185* **options** `DispatchOptions`
186* **handler** `DispatchHandler`
187
188Returns: `Boolean` - `false` if dispatcher is busy and further dispatch calls won't make any progress until the `'drain'` event has been emitted.
189
190#### Parameter: `DispatchOptions`
191
192* **origin** `string | URL`
193* **path** `string`
194* **method** `string`
195* **reset** `boolean` (optional) - Default: `false` - If `false`, the request will attempt to create a long-living connection by sending the `connection: keep-alive` header,otherwise will attempt to close it immediately after response by sending `connection: close` within the request and closing the socket afterwards.
196* **body** `string | Buffer | Uint8Array | stream.Readable | Iterable | AsyncIterable | null` (optional) - Default: `null`
197* **headers** `UndiciHeaders | string[]` (optional) - Default: `null`.
198* **query** `Record<string, any> | null` (optional) - Default: `null` - Query string params to be embedded in the request URL. Note that both keys and values of query are encoded using `encodeURIComponent`. If for some reason you need to send them unencoded, embed query params into path directly instead.
199* **idempotent** `boolean` (optional) - Default: `true` if `method` is `'HEAD'` or `'GET'` - Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline has completed.
200* **blocking** `boolean` (optional) - Default: `false` - Whether the response is expected to take a long time and would end up blocking the pipeline. When this is set to `true` further pipelining will be avoided on the same connection until headers have been received.
201* **upgrade** `string | null` (optional) - Default: `null` - Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`.
202* **bodyTimeout** `number | null` (optional) - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds.
203* **headersTimeout** `number | null` (optional) - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
204* **throwOnError** `boolean` (optional) - Default: `false` - Whether Undici should throw an error upon receiving a 4xx or 5xx response from the server.
205* **expectContinue** `boolean` (optional) - Default: `false` - For H2, it appends the expect: 100-continue header, and halts the request body until a 100-continue is received from the remote server
206
207#### Parameter: `DispatchHandler`
208
209* **onConnect** `(abort: () => void, context: object) => void` - Invoked before request is dispatched on socket. May be invoked multiple times when a request is retried when the request at the head of the pipeline fails.
210* **onError** `(error: Error) => void` - Invoked when an error has occurred. May not throw.
211* **onUpgrade** `(statusCode: number, headers: Buffer[], socket: Duplex) => void` (optional) - Invoked when request is upgraded. Required if `DispatchOptions.upgrade` is defined or `DispatchOptions.method === 'CONNECT'`.
212* **onHeaders** `(statusCode: number, headers: Buffer[], resume: () => void, statusText: string) => boolean` - Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. Not required for `upgrade` requests.
213* **onData** `(chunk: Buffer) => boolean` - Invoked when response payload data is received. Not required for `upgrade` requests.
214* **onComplete** `(trailers: Buffer[]) => void` - Invoked when response payload and trailers have been received and the request has completed. Not required for `upgrade` requests.
215* **onBodySent** `(chunk: string | Buffer | Uint8Array) => void` - Invoked when a body chunk is sent to the server. Not required. For a stream or iterable body this will be invoked for every chunk. For other body types, it will be invoked once after the body is sent.
216
217#### Example 1 - Dispatch GET request
218
219```js
220import { createServer } from 'http'
221import { Client } from 'undici'
222import { once } from 'events'
223
224const server = createServer((request, response) => {
225 response.end('Hello, World!')
226}).listen()
227
228await once(server, 'listening')
229
230const client = new Client(`http://localhost:${server.address().port}`)
231
232const data = []
233
234client.dispatch({
235 path: '/',
236 method: 'GET',
237 headers: {
238 'x-foo': 'bar'
239 }
240}, {
241 onConnect: () => {
242 console.log('Connected!')
243 },
244 onError: (error) => {
245 console.error(error)
246 },
247 onHeaders: (statusCode, headers) => {
248 console.log(`onHeaders | statusCode: ${statusCode} | headers: ${headers}`)
249 },
250 onData: (chunk) => {
251 console.log('onData: chunk received')
252 data.push(chunk)
253 },
254 onComplete: (trailers) => {
255 console.log(`onComplete | trailers: ${trailers}`)
256 const res = Buffer.concat(data).toString('utf8')
257 console.log(`Data: ${res}`)
258 client.close()
259 server.close()
260 }
261})
262```
263
264#### Example 2 - Dispatch Upgrade Request
265
266```js
267import { createServer } from 'http'
268import { Client } from 'undici'
269import { once } from 'events'
270
271const server = createServer((request, response) => {
272 response.end()
273}).listen()
274
275await once(server, 'listening')
276
277server.on('upgrade', (request, socket, head) => {
278 console.log('Node.js Server - upgrade event')
279 socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n')
280 socket.write('Upgrade: WebSocket\r\n')
281 socket.write('Connection: Upgrade\r\n')
282 socket.write('\r\n')
283 socket.end()
284})
285
286const client = new Client(`http://localhost:${server.address().port}`)
287
288client.dispatch({
289 path: '/',
290 method: 'GET',
291 upgrade: 'websocket'
292}, {
293 onConnect: () => {
294 console.log('Undici Client - onConnect')
295 },
296 onError: (error) => {
297 console.log('onError') // shouldn't print
298 },
299 onUpgrade: (statusCode, headers, socket) => {
300 console.log('Undici Client - onUpgrade')
301 console.log(`onUpgrade Headers: ${headers}`)
302 socket.on('data', buffer => {
303 console.log(buffer.toString('utf8'))
304 })
305 socket.on('end', () => {
306 client.close()
307 server.close()
308 })
309 socket.end()
310 }
311})
312```
313
314#### Example 3 - Dispatch POST request
315
316```js
317import { createServer } from 'http'
318import { Client } from 'undici'
319import { once } from 'events'
320
321const server = createServer((request, response) => {
322 request.on('data', (data) => {
323 console.log(`Request Data: ${data.toString('utf8')}`)
324 const body = JSON.parse(data)
325 body.message = 'World'
326 response.end(JSON.stringify(body))
327 })
328}).listen()
329
330await once(server, 'listening')
331
332const client = new Client(`http://localhost:${server.address().port}`)
333
334const data = []
335
336client.dispatch({
337 path: '/',
338 method: 'POST',
339 headers: {
340 'content-type': 'application/json'
341 },
342 body: JSON.stringify({ message: 'Hello' })
343}, {
344 onConnect: () => {
345 console.log('Connected!')
346 },
347 onError: (error) => {
348 console.error(error)
349 },
350 onHeaders: (statusCode, headers) => {
351 console.log(`onHeaders | statusCode: ${statusCode} | headers: ${headers}`)
352 },
353 onData: (chunk) => {
354 console.log('onData: chunk received')
355 data.push(chunk)
356 },
357 onComplete: (trailers) => {
358 console.log(`onComplete | trailers: ${trailers}`)
359 const res = Buffer.concat(data).toString('utf8')
360 console.log(`Response Data: ${res}`)
361 client.close()
362 server.close()
363 }
364})
365```
366
367### `Dispatcher.pipeline(options, handler)`
368
369For easy use with [stream.pipeline](https://nodejs.org/api/stream.html#stream_stream_pipeline_source_transforms_destination_callback). The `handler` argument should return a `Readable` from which the result will be read. Usually it should just return the `body` argument unless some kind of transformation needs to be performed based on e.g. `headers` or `statusCode`. The `handler` should validate the response and save any required state. If there is an error, it should be thrown. The function returns a `Duplex` which writes to the request and reads from the response.
370
371Arguments:
372
373* **options** `PipelineOptions`
374* **handler** `(data: PipelineHandlerData) => stream.Readable`
375
376Returns: `stream.Duplex`
377
378#### Parameter: PipelineOptions
379
380Extends: [`RequestOptions`](#parameter-requestoptions)
381
382* **objectMode** `boolean` (optional) - Default: `false` - Set to `true` if the `handler` will return an object stream.
383
384#### Parameter: PipelineHandlerData
385
386* **statusCode** `number`
387* **headers** `Record<string, string | string[] | undefined>`
388* **opaque** `unknown`
389* **body** `stream.Readable`
390* **context** `object`
391* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received.
392
393#### Example 1 - Pipeline Echo
394
395```js
396import { Readable, Writable, PassThrough, pipeline } from 'stream'
397import { createServer } from 'http'
398import { Client } from 'undici'
399import { once } from 'events'
400
401const server = createServer((request, response) => {
402 request.pipe(response)
403}).listen()
404
405await once(server, 'listening')
406
407const client = new Client(`http://localhost:${server.address().port}`)
408
409let res = ''
410
411pipeline(
412 new Readable({
413 read () {
414 this.push(Buffer.from('undici'))
415 this.push(null)
416 }
417 }),
418 client.pipeline({
419 path: '/',
420 method: 'GET'
421 }, ({ statusCode, headers, body }) => {
422 console.log(`response received ${statusCode}`)
423 console.log('headers', headers)
424 return pipeline(body, new PassThrough(), () => {})
425 }),
426 new Writable({
427 write (chunk, _, callback) {
428 res += chunk.toString()
429 callback()
430 },
431 final (callback) {
432 console.log(`Response pipelined to writable: ${res}`)
433 callback()
434 }
435 }),
436 error => {
437 if (error) {
438 console.error(error)
439 }
440
441 client.close()
442 server.close()
443 }
444)
445```
446
447### `Dispatcher.request(options[, callback])`
448
449Performs a HTTP request.
450
451Non-idempotent requests will not be pipelined in order
452to avoid indirect failures.
453
454Idempotent requests will be automatically retried if
455they fail due to indirect failure from the request
456at the head of the pipeline. This does not apply to
457idempotent requests with a stream request body.
458
459All response bodies must always be fully consumed or destroyed.
460
461Arguments:
462
463* **options** `RequestOptions`
464* **callback** `(error: Error | null, data: ResponseData) => void` (optional)
465
466Returns: `void | Promise<ResponseData>` - Only returns a `Promise` if no `callback` argument was passed.
467
468#### Parameter: `RequestOptions`
469
470Extends: [`DispatchOptions`](#parameter-dispatchoptions)
471
472* **opaque** `unknown` (optional) - Default: `null` - Used for passing through context to `ResponseData`.
473* **signal** `AbortSignal | events.EventEmitter | null` (optional) - Default: `null`.
474* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received.
475
476The `RequestOptions.method` property should not be value `'CONNECT'`.
477
478#### Parameter: `ResponseData`
479
480* **statusCode** `number`
481* **headers** `Record<string, string | string[]>` - Note that all header keys are lower-cased, e. g. `content-type`.
482* **body** `stream.Readable` which also implements [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin).
483* **trailers** `Record<string, string>` - This object starts out
484 as empty and will be mutated to contain trailers after `body` has emitted `'end'`.
485* **opaque** `unknown`
486* **context** `object`
487
488`body` contains the following additional [body mixin](https://fetch.spec.whatwg.org/#body-mixin) methods and properties:
489
490- `text()`
491- `json()`
492- `arrayBuffer()`
493- `body`
494- `bodyUsed`
495
496`body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
497
498`body` contains the following additional extensions:
499
500- `dump({ limit: Integer })`, dump the response by reading up to `limit` bytes without killing the socket (optional) - Default: 262144.
501
502Note that body will still be a `Readable` even if it is empty, but attempting to deserialize it with `json()` will result in an exception. Recommended way to ensure there is a body to deserialize is to check if status code is not 204, and `content-type` header starts with `application/json`.
503
504#### Example 1 - Basic GET Request
505
506```js
507import { createServer } from 'http'
508import { Client } from 'undici'
509import { once } from 'events'
510
511const server = createServer((request, response) => {
512 response.end('Hello, World!')
513}).listen()
514
515await once(server, 'listening')
516
517const client = new Client(`http://localhost:${server.address().port}`)
518
519try {
520 const { body, headers, statusCode, trailers } = await client.request({
521 path: '/',
522 method: 'GET'
523 })
524 console.log(`response received ${statusCode}`)
525 console.log('headers', headers)
526 body.setEncoding('utf8')
527 body.on('data', console.log)
528 body.on('end', () => {
529 console.log('trailers', trailers)
530 })
531
532 client.close()
533 server.close()
534} catch (error) {
535 console.error(error)
536}
537```
538
539#### Example 2 - Aborting a request
540
541> Node.js v15+ is required to run this example
542
543```js
544import { createServer } from 'http'
545import { Client } from 'undici'
546import { once } from 'events'
547
548const server = createServer((request, response) => {
549 response.end('Hello, World!')
550}).listen()
551
552await once(server, 'listening')
553
554const client = new Client(`http://localhost:${server.address().port}`)
555const abortController = new AbortController()
556
557try {
558 client.request({
559 path: '/',
560 method: 'GET',
561 signal: abortController.signal
562 })
563} catch (error) {
564 console.error(error) // should print an RequestAbortedError
565 client.close()
566 server.close()
567}
568
569abortController.abort()
570```
571
572Alternatively, any `EventEmitter` that emits an `'abort'` event may be used as an abort controller:
573
574```js
575import { createServer } from 'http'
576import { Client } from 'undici'
577import EventEmitter, { once } from 'events'
578
579const server = createServer((request, response) => {
580 response.end('Hello, World!')
581}).listen()
582
583await once(server, 'listening')
584
585const client = new Client(`http://localhost:${server.address().port}`)
586const ee = new EventEmitter()
587
588try {
589 client.request({
590 path: '/',
591 method: 'GET',
592 signal: ee
593 })
594} catch (error) {
595 console.error(error) // should print an RequestAbortedError
596 client.close()
597 server.close()
598}
599
600ee.emit('abort')
601```
602
603Destroying the request or response body will have the same effect.
604
605```js
606import { createServer } from 'http'
607import { Client } from 'undici'
608import { once } from 'events'
609
610const server = createServer((request, response) => {
611 response.end('Hello, World!')
612}).listen()
613
614await once(server, 'listening')
615
616const client = new Client(`http://localhost:${server.address().port}`)
617
618try {
619 const { body } = await client.request({
620 path: '/',
621 method: 'GET'
622 })
623 body.destroy()
624} catch (error) {
625 console.error(error) // should print an RequestAbortedError
626 client.close()
627 server.close()
628}
629```
630
631### `Dispatcher.stream(options, factory[, callback])`
632
633A faster version of `Dispatcher.request`. This method expects the second argument `factory` to return a [`stream.Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable) stream which the response will be written to. This improves performance by avoiding creating an intermediate [`stream.Readable`](https://nodejs.org/api/stream.html#stream_readable_streams) stream when the user expects to directly pipe the response body to a [`stream.Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable) stream.
634
635As demonstrated in [Example 1 - Basic GET stream request](#example-1---basic-get-stream-request), it is recommended to use the `option.opaque` property to avoid creating a closure for the `factory` method. This pattern works well with Node.js Web Frameworks such as [Fastify](https://fastify.io). See [Example 2 - Stream to Fastify Response](#example-2---stream-to-fastify-response) for more details.
636
637Arguments:
638
639* **options** `RequestOptions`
640* **factory** `(data: StreamFactoryData) => stream.Writable`
641* **callback** `(error: Error | null, data: StreamData) => void` (optional)
642
643Returns: `void | Promise<StreamData>` - Only returns a `Promise` if no `callback` argument was passed
644
645#### Parameter: `StreamFactoryData`
646
647* **statusCode** `number`
648* **headers** `Record<string, string | string[] | undefined>`
649* **opaque** `unknown`
650* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received.
651
652#### Parameter: `StreamData`
653
654* **opaque** `unknown`
655* **trailers** `Record<string, string>`
656* **context** `object`
657
658#### Example 1 - Basic GET stream request
659
660```js
661import { createServer } from 'http'
662import { Client } from 'undici'
663import { once } from 'events'
664import { Writable } from 'stream'
665
666const server = createServer((request, response) => {
667 response.end('Hello, World!')
668}).listen()
669
670await once(server, 'listening')
671
672const client = new Client(`http://localhost:${server.address().port}`)
673
674const bufs = []
675
676try {
677 await client.stream({
678 path: '/',
679 method: 'GET',
680 opaque: { bufs }
681 }, ({ statusCode, headers, opaque: { bufs } }) => {
682 console.log(`response received ${statusCode}`)
683 console.log('headers', headers)
684 return new Writable({
685 write (chunk, encoding, callback) {
686 bufs.push(chunk)
687 callback()
688 }
689 })
690 })
691
692 console.log(Buffer.concat(bufs).toString('utf-8'))
693
694 client.close()
695 server.close()
696} catch (error) {
697 console.error(error)
698}
699```
700
701#### Example 2 - Stream to Fastify Response
702
703In this example, a (fake) request is made to the fastify server using `fastify.inject()`. This request then executes the fastify route handler which makes a subsequent request to the raw Node.js http server using `undici.dispatcher.stream()`. The fastify response is passed to the `opaque` option so that undici can tap into the underlying writable stream using `response.raw`. This methodology demonstrates how one could use undici and fastify together to create fast-as-possible requests from one backend server to another.
704
705```js
706import { createServer } from 'http'
707import { Client } from 'undici'
708import { once } from 'events'
709import fastify from 'fastify'
710
711const nodeServer = createServer((request, response) => {
712 response.end('Hello, World! From Node.js HTTP Server')
713}).listen()
714
715await once(nodeServer, 'listening')
716
717console.log('Node Server listening')
718
719const nodeServerUndiciClient = new Client(`http://localhost:${nodeServer.address().port}`)
720
721const fastifyServer = fastify()
722
723fastifyServer.route({
724 url: '/',
725 method: 'GET',
726 handler: (request, response) => {
727 nodeServerUndiciClient.stream({
728 path: '/',
729 method: 'GET',
730 opaque: response
731 }, ({ opaque }) => opaque.raw)
732 }
733})
734
735await fastifyServer.listen()
736
737console.log('Fastify Server listening')
738
739const fastifyServerUndiciClient = new Client(`http://localhost:${fastifyServer.server.address().port}`)
740
741try {
742 const { statusCode, body } = await fastifyServerUndiciClient.request({
743 path: '/',
744 method: 'GET'
745 })
746
747 console.log(`response received ${statusCode}`)
748 body.setEncoding('utf8')
749 body.on('data', console.log)
750
751 nodeServerUndiciClient.close()
752 fastifyServerUndiciClient.close()
753 fastifyServer.close()
754 nodeServer.close()
755} catch (error) { }
756```
757
758### `Dispatcher.upgrade(options[, callback])`
759
760Upgrade to a different protocol. Visit [MDN - HTTP - Protocol upgrade mechanism](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) for more details.
761
762Arguments:
763
764* **options** `UpgradeOptions`
765
766* **callback** `(error: Error | null, data: UpgradeData) => void` (optional)
767
768Returns: `void | Promise<UpgradeData>` - Only returns a `Promise` if no `callback` argument was passed
769
770#### Parameter: `UpgradeOptions`
771
772* **path** `string`
773* **method** `string` (optional) - Default: `'GET'`
774* **headers** `UndiciHeaders` (optional) - Default: `null`
775* **protocol** `string` (optional) - Default: `'Websocket'` - A string of comma separated protocols, in descending preference order.
776* **signal** `AbortSignal | EventEmitter | null` (optional) - Default: `null`
777
778#### Parameter: `UpgradeData`
779
780* **headers** `http.IncomingHeaders`
781* **socket** `stream.Duplex`
782* **opaque** `unknown`
783
784#### Example 1 - Basic Upgrade Request
785
786```js
787import { createServer } from 'http'
788import { Client } from 'undici'
789import { once } from 'events'
790
791const server = createServer((request, response) => {
792 response.statusCode = 101
793 response.setHeader('connection', 'upgrade')
794 response.setHeader('upgrade', request.headers.upgrade)
795 response.end()
796}).listen()
797
798await once(server, 'listening')
799
800const client = new Client(`http://localhost:${server.address().port}`)
801
802try {
803 const { headers, socket } = await client.upgrade({
804 path: '/',
805 })
806 socket.on('end', () => {
807 console.log(`upgrade: ${headers.upgrade}`) // upgrade: Websocket
808 client.close()
809 server.close()
810 })
811 socket.end()
812} catch (error) {
813 console.error(error)
814 client.close()
815 server.close()
816}
817```
818
819## Instance Events
820
821### Event: `'connect'`
822
823Parameters:
824
825* **origin** `URL`
826* **targets** `Array<Dispatcher>`
827
828### Event: `'disconnect'`
829
830Parameters:
831
832* **origin** `URL`
833* **targets** `Array<Dispatcher>`
834* **error** `Error`
835
836### Event: `'connectionError'`
837
838Parameters:
839
840* **origin** `URL`
841* **targets** `Array<Dispatcher>`
842* **error** `Error`
843
844Emitted when dispatcher fails to connect to
845origin.
846
847### Event: `'drain'`
848
849Parameters:
850
851* **origin** `URL`
852
853Emitted when dispatcher is no longer busy.
854
855## Parameter: `UndiciHeaders`
856
857* `Record<string, string | string[] | undefined> | string[] | null`
858
859Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in two forms; either as an object specified by the `Record<string, string | string[] | undefined>` (`IncomingHttpHeaders`) type, or an array of strings. An array representation of a header list must have an even length or an `InvalidArgumentError` will be thrown.
860
861Keys are lowercase and values are not modified.
862
863Response headers will derive a `host` from the `url` of the [Client](Client.md#class-client) instance if no `host` header was previously specified.
864
865### Example 1 - Object
866
867```js
868{
869 'content-length': '123',
870 'content-type': 'text/plain',
871 connection: 'keep-alive',
872 host: 'mysite.com',
873 accept: '*/*'
874}
875```
876
877### Example 2 - Array
878
879```js
880[
881 'content-length', '123',
882 'content-type', 'text/plain',
883 'connection', 'keep-alive',
884 'host', 'mysite.com',
885 'accept', '*/*'
886]
887```
Note: See TracBrowser for help on using the repository browser.