11cb0ef41Sopenharmony_ci# Dispatcher 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciExtends: `events.EventEmitter` 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciDispatcher is the core API used to dispatch requests. 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciRequests are not guaranteed to be dispatched in order of invocation. 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci## Instance Methods 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci### `Dispatcher.close([callback]): Promise` 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ciCloses the dispatcher and gracefully waits for enqueued requests to complete before resolving. 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciArguments: 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci* **callback** `(error: Error | null, data: null) => void` (optional) 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciReturns: `void | Promise<null>` - Only returns a `Promise` if no `callback` argument was passed 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci```js 221cb0ef41Sopenharmony_cidispatcher.close() // -> Promise 231cb0ef41Sopenharmony_cidispatcher.close(() => {}) // -> void 241cb0ef41Sopenharmony_ci``` 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#### Example - Request resolves before Client closes 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci```js 291cb0ef41Sopenharmony_ciimport { createServer } from 'http' 301cb0ef41Sopenharmony_ciimport { Client } from 'undici' 311cb0ef41Sopenharmony_ciimport { once } from 'events' 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 341cb0ef41Sopenharmony_ci response.end('undici') 351cb0ef41Sopenharmony_ci}).listen() 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciawait once(server, 'listening') 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_citry { 421cb0ef41Sopenharmony_ci const { body } = await client.request({ 431cb0ef41Sopenharmony_ci path: '/', 441cb0ef41Sopenharmony_ci method: 'GET' 451cb0ef41Sopenharmony_ci }) 461cb0ef41Sopenharmony_ci body.setEncoding('utf8') 471cb0ef41Sopenharmony_ci body.on('data', console.log) 481cb0ef41Sopenharmony_ci} catch (error) {} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ciawait client.close() 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciconsole.log('Client closed') 531cb0ef41Sopenharmony_ciserver.close() 541cb0ef41Sopenharmony_ci``` 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci### `Dispatcher.connect(options[, callback])` 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ciStarts two-way communications with the requested resource using [HTTP CONNECT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT). 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ciArguments: 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci* **options** `ConnectOptions` 631cb0ef41Sopenharmony_ci* **callback** `(err: Error | null, data: ConnectData | null) => void` (optional) 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ciReturns: `void | Promise<ConnectData>` - Only returns a `Promise` if no `callback` argument was passed 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci#### Parameter: `ConnectOptions` 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci* **path** `string` 701cb0ef41Sopenharmony_ci* **headers** `UndiciHeaders` (optional) - Default: `null` 711cb0ef41Sopenharmony_ci* **signal** `AbortSignal | events.EventEmitter | null` (optional) - Default: `null` 721cb0ef41Sopenharmony_ci* **opaque** `unknown` (optional) - This argument parameter is passed through to `ConnectData` 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci#### Parameter: `ConnectData` 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci* **statusCode** `number` 771cb0ef41Sopenharmony_ci* **headers** `Record<string, string | string[] | undefined>` 781cb0ef41Sopenharmony_ci* **socket** `stream.Duplex` 791cb0ef41Sopenharmony_ci* **opaque** `unknown` 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci#### Example - Connect request with echo 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci```js 841cb0ef41Sopenharmony_ciimport { createServer } from 'http' 851cb0ef41Sopenharmony_ciimport { Client } from 'undici' 861cb0ef41Sopenharmony_ciimport { once } from 'events' 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 891cb0ef41Sopenharmony_ci throw Error('should never get here') 901cb0ef41Sopenharmony_ci}).listen() 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ciserver.on('connect', (req, socket, head) => { 931cb0ef41Sopenharmony_ci socket.write('HTTP/1.1 200 Connection established\r\n\r\n') 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci let data = head.toString() 961cb0ef41Sopenharmony_ci socket.on('data', (buf) => { 971cb0ef41Sopenharmony_ci data += buf.toString() 981cb0ef41Sopenharmony_ci }) 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci socket.on('end', () => { 1011cb0ef41Sopenharmony_ci socket.end(data) 1021cb0ef41Sopenharmony_ci }) 1031cb0ef41Sopenharmony_ci}) 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ciawait once(server, 'listening') 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_citry { 1101cb0ef41Sopenharmony_ci const { socket } = await client.connect({ 1111cb0ef41Sopenharmony_ci path: '/' 1121cb0ef41Sopenharmony_ci }) 1131cb0ef41Sopenharmony_ci const wanted = 'Body' 1141cb0ef41Sopenharmony_ci let data = '' 1151cb0ef41Sopenharmony_ci socket.on('data', d => { data += d }) 1161cb0ef41Sopenharmony_ci socket.on('end', () => { 1171cb0ef41Sopenharmony_ci console.log(`Data received: ${data.toString()} | Data wanted: ${wanted}`) 1181cb0ef41Sopenharmony_ci client.close() 1191cb0ef41Sopenharmony_ci server.close() 1201cb0ef41Sopenharmony_ci }) 1211cb0ef41Sopenharmony_ci socket.write(wanted) 1221cb0ef41Sopenharmony_ci socket.end() 1231cb0ef41Sopenharmony_ci} catch (error) { } 1241cb0ef41Sopenharmony_ci``` 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci### `Dispatcher.destroy([error, callback]): Promise` 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ciDestroy 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. 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ciBoth arguments are optional; the method can be called in four different ways: 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ciArguments: 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci* **error** `Error | null` (optional) 1351cb0ef41Sopenharmony_ci* **callback** `(error: Error | null, data: null) => void` (optional) 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ciReturns: `void | Promise<void>` - Only returns a `Promise` if no `callback` argument was passed 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci```js 1401cb0ef41Sopenharmony_cidispatcher.destroy() // -> Promise 1411cb0ef41Sopenharmony_cidispatcher.destroy(new Error()) // -> Promise 1421cb0ef41Sopenharmony_cidispatcher.destroy(() => {}) // -> void 1431cb0ef41Sopenharmony_cidispatcher.destroy(new Error(), () => {}) // -> void 1441cb0ef41Sopenharmony_ci``` 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci#### Example - Request is aborted when Client is destroyed 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci```js 1491cb0ef41Sopenharmony_ciimport { createServer } from 'http' 1501cb0ef41Sopenharmony_ciimport { Client } from 'undici' 1511cb0ef41Sopenharmony_ciimport { once } from 'events' 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 1541cb0ef41Sopenharmony_ci response.end() 1551cb0ef41Sopenharmony_ci}).listen() 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ciawait once(server, 'listening') 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_citry { 1621cb0ef41Sopenharmony_ci const request = client.request({ 1631cb0ef41Sopenharmony_ci path: '/', 1641cb0ef41Sopenharmony_ci method: 'GET' 1651cb0ef41Sopenharmony_ci }) 1661cb0ef41Sopenharmony_ci client.destroy() 1671cb0ef41Sopenharmony_ci .then(() => { 1681cb0ef41Sopenharmony_ci console.log('Client destroyed') 1691cb0ef41Sopenharmony_ci server.close() 1701cb0ef41Sopenharmony_ci }) 1711cb0ef41Sopenharmony_ci await request 1721cb0ef41Sopenharmony_ci} catch (error) { 1731cb0ef41Sopenharmony_ci console.error(error) 1741cb0ef41Sopenharmony_ci} 1751cb0ef41Sopenharmony_ci``` 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci### `Dispatcher.dispatch(options, handler)` 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ciThis is the low level API which all the preceding APIs are implemented on top of. 1801cb0ef41Sopenharmony_ciThis API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs. 1811cb0ef41Sopenharmony_ciIt is primarily intended for library developers who implement higher level APIs on top of this. 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ciArguments: 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci* **options** `DispatchOptions` 1861cb0ef41Sopenharmony_ci* **handler** `DispatchHandler` 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ciReturns: `Boolean` - `false` if dispatcher is busy and further dispatch calls won't make any progress until the `'drain'` event has been emitted. 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci#### Parameter: `DispatchOptions` 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci* **origin** `string | URL` 1931cb0ef41Sopenharmony_ci* **path** `string` 1941cb0ef41Sopenharmony_ci* **method** `string` 1951cb0ef41Sopenharmony_ci* **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. 1961cb0ef41Sopenharmony_ci* **body** `string | Buffer | Uint8Array | stream.Readable | Iterable | AsyncIterable | null` (optional) - Default: `null` 1971cb0ef41Sopenharmony_ci* **headers** `UndiciHeaders | string[]` (optional) - Default: `null`. 1981cb0ef41Sopenharmony_ci* **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. 1991cb0ef41Sopenharmony_ci* **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. 2001cb0ef41Sopenharmony_ci* **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. 2011cb0ef41Sopenharmony_ci* **upgrade** `string | null` (optional) - Default: `null` - Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`. 2021cb0ef41Sopenharmony_ci* **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. 2031cb0ef41Sopenharmony_ci* **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. 2041cb0ef41Sopenharmony_ci* **throwOnError** `boolean` (optional) - Default: `false` - Whether Undici should throw an error upon receiving a 4xx or 5xx response from the server. 2051cb0ef41Sopenharmony_ci* **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 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci#### Parameter: `DispatchHandler` 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci* **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. 2101cb0ef41Sopenharmony_ci* **onError** `(error: Error) => void` - Invoked when an error has occurred. May not throw. 2111cb0ef41Sopenharmony_ci* **onUpgrade** `(statusCode: number, headers: Buffer[], socket: Duplex) => void` (optional) - Invoked when request is upgraded. Required if `DispatchOptions.upgrade` is defined or `DispatchOptions.method === 'CONNECT'`. 2121cb0ef41Sopenharmony_ci* **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. 2131cb0ef41Sopenharmony_ci* **onData** `(chunk: Buffer) => boolean` - Invoked when response payload data is received. Not required for `upgrade` requests. 2141cb0ef41Sopenharmony_ci* **onComplete** `(trailers: Buffer[]) => void` - Invoked when response payload and trailers have been received and the request has completed. Not required for `upgrade` requests. 2151cb0ef41Sopenharmony_ci* **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. 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci#### Example 1 - Dispatch GET request 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci```js 2201cb0ef41Sopenharmony_ciimport { createServer } from 'http' 2211cb0ef41Sopenharmony_ciimport { Client } from 'undici' 2221cb0ef41Sopenharmony_ciimport { once } from 'events' 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 2251cb0ef41Sopenharmony_ci response.end('Hello, World!') 2261cb0ef41Sopenharmony_ci}).listen() 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ciawait once(server, 'listening') 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ciconst data = [] 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ciclient.dispatch({ 2351cb0ef41Sopenharmony_ci path: '/', 2361cb0ef41Sopenharmony_ci method: 'GET', 2371cb0ef41Sopenharmony_ci headers: { 2381cb0ef41Sopenharmony_ci 'x-foo': 'bar' 2391cb0ef41Sopenharmony_ci } 2401cb0ef41Sopenharmony_ci}, { 2411cb0ef41Sopenharmony_ci onConnect: () => { 2421cb0ef41Sopenharmony_ci console.log('Connected!') 2431cb0ef41Sopenharmony_ci }, 2441cb0ef41Sopenharmony_ci onError: (error) => { 2451cb0ef41Sopenharmony_ci console.error(error) 2461cb0ef41Sopenharmony_ci }, 2471cb0ef41Sopenharmony_ci onHeaders: (statusCode, headers) => { 2481cb0ef41Sopenharmony_ci console.log(`onHeaders | statusCode: ${statusCode} | headers: ${headers}`) 2491cb0ef41Sopenharmony_ci }, 2501cb0ef41Sopenharmony_ci onData: (chunk) => { 2511cb0ef41Sopenharmony_ci console.log('onData: chunk received') 2521cb0ef41Sopenharmony_ci data.push(chunk) 2531cb0ef41Sopenharmony_ci }, 2541cb0ef41Sopenharmony_ci onComplete: (trailers) => { 2551cb0ef41Sopenharmony_ci console.log(`onComplete | trailers: ${trailers}`) 2561cb0ef41Sopenharmony_ci const res = Buffer.concat(data).toString('utf8') 2571cb0ef41Sopenharmony_ci console.log(`Data: ${res}`) 2581cb0ef41Sopenharmony_ci client.close() 2591cb0ef41Sopenharmony_ci server.close() 2601cb0ef41Sopenharmony_ci } 2611cb0ef41Sopenharmony_ci}) 2621cb0ef41Sopenharmony_ci``` 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci#### Example 2 - Dispatch Upgrade Request 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci```js 2671cb0ef41Sopenharmony_ciimport { createServer } from 'http' 2681cb0ef41Sopenharmony_ciimport { Client } from 'undici' 2691cb0ef41Sopenharmony_ciimport { once } from 'events' 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 2721cb0ef41Sopenharmony_ci response.end() 2731cb0ef41Sopenharmony_ci}).listen() 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ciawait once(server, 'listening') 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ciserver.on('upgrade', (request, socket, head) => { 2781cb0ef41Sopenharmony_ci console.log('Node.js Server - upgrade event') 2791cb0ef41Sopenharmony_ci socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n') 2801cb0ef41Sopenharmony_ci socket.write('Upgrade: WebSocket\r\n') 2811cb0ef41Sopenharmony_ci socket.write('Connection: Upgrade\r\n') 2821cb0ef41Sopenharmony_ci socket.write('\r\n') 2831cb0ef41Sopenharmony_ci socket.end() 2841cb0ef41Sopenharmony_ci}) 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ciclient.dispatch({ 2891cb0ef41Sopenharmony_ci path: '/', 2901cb0ef41Sopenharmony_ci method: 'GET', 2911cb0ef41Sopenharmony_ci upgrade: 'websocket' 2921cb0ef41Sopenharmony_ci}, { 2931cb0ef41Sopenharmony_ci onConnect: () => { 2941cb0ef41Sopenharmony_ci console.log('Undici Client - onConnect') 2951cb0ef41Sopenharmony_ci }, 2961cb0ef41Sopenharmony_ci onError: (error) => { 2971cb0ef41Sopenharmony_ci console.log('onError') // shouldn't print 2981cb0ef41Sopenharmony_ci }, 2991cb0ef41Sopenharmony_ci onUpgrade: (statusCode, headers, socket) => { 3001cb0ef41Sopenharmony_ci console.log('Undici Client - onUpgrade') 3011cb0ef41Sopenharmony_ci console.log(`onUpgrade Headers: ${headers}`) 3021cb0ef41Sopenharmony_ci socket.on('data', buffer => { 3031cb0ef41Sopenharmony_ci console.log(buffer.toString('utf8')) 3041cb0ef41Sopenharmony_ci }) 3051cb0ef41Sopenharmony_ci socket.on('end', () => { 3061cb0ef41Sopenharmony_ci client.close() 3071cb0ef41Sopenharmony_ci server.close() 3081cb0ef41Sopenharmony_ci }) 3091cb0ef41Sopenharmony_ci socket.end() 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci}) 3121cb0ef41Sopenharmony_ci``` 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci#### Example 3 - Dispatch POST request 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci```js 3171cb0ef41Sopenharmony_ciimport { createServer } from 'http' 3181cb0ef41Sopenharmony_ciimport { Client } from 'undici' 3191cb0ef41Sopenharmony_ciimport { once } from 'events' 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 3221cb0ef41Sopenharmony_ci request.on('data', (data) => { 3231cb0ef41Sopenharmony_ci console.log(`Request Data: ${data.toString('utf8')}`) 3241cb0ef41Sopenharmony_ci const body = JSON.parse(data) 3251cb0ef41Sopenharmony_ci body.message = 'World' 3261cb0ef41Sopenharmony_ci response.end(JSON.stringify(body)) 3271cb0ef41Sopenharmony_ci }) 3281cb0ef41Sopenharmony_ci}).listen() 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_ciawait once(server, 'listening') 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ciconst data = [] 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ciclient.dispatch({ 3371cb0ef41Sopenharmony_ci path: '/', 3381cb0ef41Sopenharmony_ci method: 'POST', 3391cb0ef41Sopenharmony_ci headers: { 3401cb0ef41Sopenharmony_ci 'content-type': 'application/json' 3411cb0ef41Sopenharmony_ci }, 3421cb0ef41Sopenharmony_ci body: JSON.stringify({ message: 'Hello' }) 3431cb0ef41Sopenharmony_ci}, { 3441cb0ef41Sopenharmony_ci onConnect: () => { 3451cb0ef41Sopenharmony_ci console.log('Connected!') 3461cb0ef41Sopenharmony_ci }, 3471cb0ef41Sopenharmony_ci onError: (error) => { 3481cb0ef41Sopenharmony_ci console.error(error) 3491cb0ef41Sopenharmony_ci }, 3501cb0ef41Sopenharmony_ci onHeaders: (statusCode, headers) => { 3511cb0ef41Sopenharmony_ci console.log(`onHeaders | statusCode: ${statusCode} | headers: ${headers}`) 3521cb0ef41Sopenharmony_ci }, 3531cb0ef41Sopenharmony_ci onData: (chunk) => { 3541cb0ef41Sopenharmony_ci console.log('onData: chunk received') 3551cb0ef41Sopenharmony_ci data.push(chunk) 3561cb0ef41Sopenharmony_ci }, 3571cb0ef41Sopenharmony_ci onComplete: (trailers) => { 3581cb0ef41Sopenharmony_ci console.log(`onComplete | trailers: ${trailers}`) 3591cb0ef41Sopenharmony_ci const res = Buffer.concat(data).toString('utf8') 3601cb0ef41Sopenharmony_ci console.log(`Response Data: ${res}`) 3611cb0ef41Sopenharmony_ci client.close() 3621cb0ef41Sopenharmony_ci server.close() 3631cb0ef41Sopenharmony_ci } 3641cb0ef41Sopenharmony_ci}) 3651cb0ef41Sopenharmony_ci``` 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci### `Dispatcher.pipeline(options, handler)` 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ciFor 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. 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ciArguments: 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_ci* **options** `PipelineOptions` 3741cb0ef41Sopenharmony_ci* **handler** `(data: PipelineHandlerData) => stream.Readable` 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ciReturns: `stream.Duplex` 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci#### Parameter: PipelineOptions 3791cb0ef41Sopenharmony_ci 3801cb0ef41Sopenharmony_ciExtends: [`RequestOptions`](#parameter-requestoptions) 3811cb0ef41Sopenharmony_ci 3821cb0ef41Sopenharmony_ci* **objectMode** `boolean` (optional) - Default: `false` - Set to `true` if the `handler` will return an object stream. 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci#### Parameter: PipelineHandlerData 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci* **statusCode** `number` 3871cb0ef41Sopenharmony_ci* **headers** `Record<string, string | string[] | undefined>` 3881cb0ef41Sopenharmony_ci* **opaque** `unknown` 3891cb0ef41Sopenharmony_ci* **body** `stream.Readable` 3901cb0ef41Sopenharmony_ci* **context** `object` 3911cb0ef41Sopenharmony_ci* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received. 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci#### Example 1 - Pipeline Echo 3941cb0ef41Sopenharmony_ci 3951cb0ef41Sopenharmony_ci```js 3961cb0ef41Sopenharmony_ciimport { Readable, Writable, PassThrough, pipeline } from 'stream' 3971cb0ef41Sopenharmony_ciimport { createServer } from 'http' 3981cb0ef41Sopenharmony_ciimport { Client } from 'undici' 3991cb0ef41Sopenharmony_ciimport { once } from 'events' 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 4021cb0ef41Sopenharmony_ci request.pipe(response) 4031cb0ef41Sopenharmony_ci}).listen() 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ciawait once(server, 'listening') 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_cilet res = '' 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_cipipeline( 4121cb0ef41Sopenharmony_ci new Readable({ 4131cb0ef41Sopenharmony_ci read () { 4141cb0ef41Sopenharmony_ci this.push(Buffer.from('undici')) 4151cb0ef41Sopenharmony_ci this.push(null) 4161cb0ef41Sopenharmony_ci } 4171cb0ef41Sopenharmony_ci }), 4181cb0ef41Sopenharmony_ci client.pipeline({ 4191cb0ef41Sopenharmony_ci path: '/', 4201cb0ef41Sopenharmony_ci method: 'GET' 4211cb0ef41Sopenharmony_ci }, ({ statusCode, headers, body }) => { 4221cb0ef41Sopenharmony_ci console.log(`response received ${statusCode}`) 4231cb0ef41Sopenharmony_ci console.log('headers', headers) 4241cb0ef41Sopenharmony_ci return pipeline(body, new PassThrough(), () => {}) 4251cb0ef41Sopenharmony_ci }), 4261cb0ef41Sopenharmony_ci new Writable({ 4271cb0ef41Sopenharmony_ci write (chunk, _, callback) { 4281cb0ef41Sopenharmony_ci res += chunk.toString() 4291cb0ef41Sopenharmony_ci callback() 4301cb0ef41Sopenharmony_ci }, 4311cb0ef41Sopenharmony_ci final (callback) { 4321cb0ef41Sopenharmony_ci console.log(`Response pipelined to writable: ${res}`) 4331cb0ef41Sopenharmony_ci callback() 4341cb0ef41Sopenharmony_ci } 4351cb0ef41Sopenharmony_ci }), 4361cb0ef41Sopenharmony_ci error => { 4371cb0ef41Sopenharmony_ci if (error) { 4381cb0ef41Sopenharmony_ci console.error(error) 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci 4411cb0ef41Sopenharmony_ci client.close() 4421cb0ef41Sopenharmony_ci server.close() 4431cb0ef41Sopenharmony_ci } 4441cb0ef41Sopenharmony_ci) 4451cb0ef41Sopenharmony_ci``` 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ci### `Dispatcher.request(options[, callback])` 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ciPerforms a HTTP request. 4501cb0ef41Sopenharmony_ci 4511cb0ef41Sopenharmony_ciNon-idempotent requests will not be pipelined in order 4521cb0ef41Sopenharmony_cito avoid indirect failures. 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ciIdempotent requests will be automatically retried if 4551cb0ef41Sopenharmony_cithey fail due to indirect failure from the request 4561cb0ef41Sopenharmony_ciat the head of the pipeline. This does not apply to 4571cb0ef41Sopenharmony_ciidempotent requests with a stream request body. 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ciAll response bodies must always be fully consumed or destroyed. 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ciArguments: 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci* **options** `RequestOptions` 4641cb0ef41Sopenharmony_ci* **callback** `(error: Error | null, data: ResponseData) => void` (optional) 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ciReturns: `void | Promise<ResponseData>` - Only returns a `Promise` if no `callback` argument was passed. 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci#### Parameter: `RequestOptions` 4691cb0ef41Sopenharmony_ci 4701cb0ef41Sopenharmony_ciExtends: [`DispatchOptions`](#parameter-dispatchoptions) 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci* **opaque** `unknown` (optional) - Default: `null` - Used for passing through context to `ResponseData`. 4731cb0ef41Sopenharmony_ci* **signal** `AbortSignal | events.EventEmitter | null` (optional) - Default: `null`. 4741cb0ef41Sopenharmony_ci* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received. 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ciThe `RequestOptions.method` property should not be value `'CONNECT'`. 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci#### Parameter: `ResponseData` 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci* **statusCode** `number` 4811cb0ef41Sopenharmony_ci* **headers** `Record<string, string | string[]>` - Note that all header keys are lower-cased, e. g. `content-type`. 4821cb0ef41Sopenharmony_ci* **body** `stream.Readable` which also implements [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin). 4831cb0ef41Sopenharmony_ci* **trailers** `Record<string, string>` - This object starts out 4841cb0ef41Sopenharmony_ci as empty and will be mutated to contain trailers after `body` has emitted `'end'`. 4851cb0ef41Sopenharmony_ci* **opaque** `unknown` 4861cb0ef41Sopenharmony_ci* **context** `object` 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci`body` contains the following additional [body mixin](https://fetch.spec.whatwg.org/#body-mixin) methods and properties: 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci- `text()` 4911cb0ef41Sopenharmony_ci- `json()` 4921cb0ef41Sopenharmony_ci- `arrayBuffer()` 4931cb0ef41Sopenharmony_ci- `body` 4941cb0ef41Sopenharmony_ci- `bodyUsed` 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci`body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`. 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci`body` contains the following additional extensions: 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_ci- `dump({ limit: Integer })`, dump the response by reading up to `limit` bytes without killing the socket (optional) - Default: 262144. 5011cb0ef41Sopenharmony_ci 5021cb0ef41Sopenharmony_ciNote 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`. 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci#### Example 1 - Basic GET Request 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ci```js 5071cb0ef41Sopenharmony_ciimport { createServer } from 'http' 5081cb0ef41Sopenharmony_ciimport { Client } from 'undici' 5091cb0ef41Sopenharmony_ciimport { once } from 'events' 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 5121cb0ef41Sopenharmony_ci response.end('Hello, World!') 5131cb0ef41Sopenharmony_ci}).listen() 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ciawait once(server, 'listening') 5161cb0ef41Sopenharmony_ci 5171cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_citry { 5201cb0ef41Sopenharmony_ci const { body, headers, statusCode, trailers } = await client.request({ 5211cb0ef41Sopenharmony_ci path: '/', 5221cb0ef41Sopenharmony_ci method: 'GET' 5231cb0ef41Sopenharmony_ci }) 5241cb0ef41Sopenharmony_ci console.log(`response received ${statusCode}`) 5251cb0ef41Sopenharmony_ci console.log('headers', headers) 5261cb0ef41Sopenharmony_ci body.setEncoding('utf8') 5271cb0ef41Sopenharmony_ci body.on('data', console.log) 5281cb0ef41Sopenharmony_ci body.on('end', () => { 5291cb0ef41Sopenharmony_ci console.log('trailers', trailers) 5301cb0ef41Sopenharmony_ci }) 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_ci client.close() 5331cb0ef41Sopenharmony_ci server.close() 5341cb0ef41Sopenharmony_ci} catch (error) { 5351cb0ef41Sopenharmony_ci console.error(error) 5361cb0ef41Sopenharmony_ci} 5371cb0ef41Sopenharmony_ci``` 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_ci#### Example 2 - Aborting a request 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ci> Node.js v15+ is required to run this example 5421cb0ef41Sopenharmony_ci 5431cb0ef41Sopenharmony_ci```js 5441cb0ef41Sopenharmony_ciimport { createServer } from 'http' 5451cb0ef41Sopenharmony_ciimport { Client } from 'undici' 5461cb0ef41Sopenharmony_ciimport { once } from 'events' 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 5491cb0ef41Sopenharmony_ci response.end('Hello, World!') 5501cb0ef41Sopenharmony_ci}).listen() 5511cb0ef41Sopenharmony_ci 5521cb0ef41Sopenharmony_ciawait once(server, 'listening') 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 5551cb0ef41Sopenharmony_ciconst abortController = new AbortController() 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_citry { 5581cb0ef41Sopenharmony_ci client.request({ 5591cb0ef41Sopenharmony_ci path: '/', 5601cb0ef41Sopenharmony_ci method: 'GET', 5611cb0ef41Sopenharmony_ci signal: abortController.signal 5621cb0ef41Sopenharmony_ci }) 5631cb0ef41Sopenharmony_ci} catch (error) { 5641cb0ef41Sopenharmony_ci console.error(error) // should print an RequestAbortedError 5651cb0ef41Sopenharmony_ci client.close() 5661cb0ef41Sopenharmony_ci server.close() 5671cb0ef41Sopenharmony_ci} 5681cb0ef41Sopenharmony_ci 5691cb0ef41Sopenharmony_ciabortController.abort() 5701cb0ef41Sopenharmony_ci``` 5711cb0ef41Sopenharmony_ci 5721cb0ef41Sopenharmony_ciAlternatively, any `EventEmitter` that emits an `'abort'` event may be used as an abort controller: 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ci```js 5751cb0ef41Sopenharmony_ciimport { createServer } from 'http' 5761cb0ef41Sopenharmony_ciimport { Client } from 'undici' 5771cb0ef41Sopenharmony_ciimport EventEmitter, { once } from 'events' 5781cb0ef41Sopenharmony_ci 5791cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 5801cb0ef41Sopenharmony_ci response.end('Hello, World!') 5811cb0ef41Sopenharmony_ci}).listen() 5821cb0ef41Sopenharmony_ci 5831cb0ef41Sopenharmony_ciawait once(server, 'listening') 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 5861cb0ef41Sopenharmony_ciconst ee = new EventEmitter() 5871cb0ef41Sopenharmony_ci 5881cb0ef41Sopenharmony_citry { 5891cb0ef41Sopenharmony_ci client.request({ 5901cb0ef41Sopenharmony_ci path: '/', 5911cb0ef41Sopenharmony_ci method: 'GET', 5921cb0ef41Sopenharmony_ci signal: ee 5931cb0ef41Sopenharmony_ci }) 5941cb0ef41Sopenharmony_ci} catch (error) { 5951cb0ef41Sopenharmony_ci console.error(error) // should print an RequestAbortedError 5961cb0ef41Sopenharmony_ci client.close() 5971cb0ef41Sopenharmony_ci server.close() 5981cb0ef41Sopenharmony_ci} 5991cb0ef41Sopenharmony_ci 6001cb0ef41Sopenharmony_ciee.emit('abort') 6011cb0ef41Sopenharmony_ci``` 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ciDestroying the request or response body will have the same effect. 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_ci```js 6061cb0ef41Sopenharmony_ciimport { createServer } from 'http' 6071cb0ef41Sopenharmony_ciimport { Client } from 'undici' 6081cb0ef41Sopenharmony_ciimport { once } from 'events' 6091cb0ef41Sopenharmony_ci 6101cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 6111cb0ef41Sopenharmony_ci response.end('Hello, World!') 6121cb0ef41Sopenharmony_ci}).listen() 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ciawait once(server, 'listening') 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_citry { 6191cb0ef41Sopenharmony_ci const { body } = await client.request({ 6201cb0ef41Sopenharmony_ci path: '/', 6211cb0ef41Sopenharmony_ci method: 'GET' 6221cb0ef41Sopenharmony_ci }) 6231cb0ef41Sopenharmony_ci body.destroy() 6241cb0ef41Sopenharmony_ci} catch (error) { 6251cb0ef41Sopenharmony_ci console.error(error) // should print an RequestAbortedError 6261cb0ef41Sopenharmony_ci client.close() 6271cb0ef41Sopenharmony_ci server.close() 6281cb0ef41Sopenharmony_ci} 6291cb0ef41Sopenharmony_ci``` 6301cb0ef41Sopenharmony_ci 6311cb0ef41Sopenharmony_ci### `Dispatcher.stream(options, factory[, callback])` 6321cb0ef41Sopenharmony_ci 6331cb0ef41Sopenharmony_ciA 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. 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ciAs 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. 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ciArguments: 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_ci* **options** `RequestOptions` 6401cb0ef41Sopenharmony_ci* **factory** `(data: StreamFactoryData) => stream.Writable` 6411cb0ef41Sopenharmony_ci* **callback** `(error: Error | null, data: StreamData) => void` (optional) 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ciReturns: `void | Promise<StreamData>` - Only returns a `Promise` if no `callback` argument was passed 6441cb0ef41Sopenharmony_ci 6451cb0ef41Sopenharmony_ci#### Parameter: `StreamFactoryData` 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci* **statusCode** `number` 6481cb0ef41Sopenharmony_ci* **headers** `Record<string, string | string[] | undefined>` 6491cb0ef41Sopenharmony_ci* **opaque** `unknown` 6501cb0ef41Sopenharmony_ci* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received. 6511cb0ef41Sopenharmony_ci 6521cb0ef41Sopenharmony_ci#### Parameter: `StreamData` 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci* **opaque** `unknown` 6551cb0ef41Sopenharmony_ci* **trailers** `Record<string, string>` 6561cb0ef41Sopenharmony_ci* **context** `object` 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ci#### Example 1 - Basic GET stream request 6591cb0ef41Sopenharmony_ci 6601cb0ef41Sopenharmony_ci```js 6611cb0ef41Sopenharmony_ciimport { createServer } from 'http' 6621cb0ef41Sopenharmony_ciimport { Client } from 'undici' 6631cb0ef41Sopenharmony_ciimport { once } from 'events' 6641cb0ef41Sopenharmony_ciimport { Writable } from 'stream' 6651cb0ef41Sopenharmony_ci 6661cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 6671cb0ef41Sopenharmony_ci response.end('Hello, World!') 6681cb0ef41Sopenharmony_ci}).listen() 6691cb0ef41Sopenharmony_ci 6701cb0ef41Sopenharmony_ciawait once(server, 'listening') 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 6731cb0ef41Sopenharmony_ci 6741cb0ef41Sopenharmony_ciconst bufs = [] 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_citry { 6771cb0ef41Sopenharmony_ci await client.stream({ 6781cb0ef41Sopenharmony_ci path: '/', 6791cb0ef41Sopenharmony_ci method: 'GET', 6801cb0ef41Sopenharmony_ci opaque: { bufs } 6811cb0ef41Sopenharmony_ci }, ({ statusCode, headers, opaque: { bufs } }) => { 6821cb0ef41Sopenharmony_ci console.log(`response received ${statusCode}`) 6831cb0ef41Sopenharmony_ci console.log('headers', headers) 6841cb0ef41Sopenharmony_ci return new Writable({ 6851cb0ef41Sopenharmony_ci write (chunk, encoding, callback) { 6861cb0ef41Sopenharmony_ci bufs.push(chunk) 6871cb0ef41Sopenharmony_ci callback() 6881cb0ef41Sopenharmony_ci } 6891cb0ef41Sopenharmony_ci }) 6901cb0ef41Sopenharmony_ci }) 6911cb0ef41Sopenharmony_ci 6921cb0ef41Sopenharmony_ci console.log(Buffer.concat(bufs).toString('utf-8')) 6931cb0ef41Sopenharmony_ci 6941cb0ef41Sopenharmony_ci client.close() 6951cb0ef41Sopenharmony_ci server.close() 6961cb0ef41Sopenharmony_ci} catch (error) { 6971cb0ef41Sopenharmony_ci console.error(error) 6981cb0ef41Sopenharmony_ci} 6991cb0ef41Sopenharmony_ci``` 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_ci#### Example 2 - Stream to Fastify Response 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_ciIn 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. 7041cb0ef41Sopenharmony_ci 7051cb0ef41Sopenharmony_ci```js 7061cb0ef41Sopenharmony_ciimport { createServer } from 'http' 7071cb0ef41Sopenharmony_ciimport { Client } from 'undici' 7081cb0ef41Sopenharmony_ciimport { once } from 'events' 7091cb0ef41Sopenharmony_ciimport fastify from 'fastify' 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ciconst nodeServer = createServer((request, response) => { 7121cb0ef41Sopenharmony_ci response.end('Hello, World! From Node.js HTTP Server') 7131cb0ef41Sopenharmony_ci}).listen() 7141cb0ef41Sopenharmony_ci 7151cb0ef41Sopenharmony_ciawait once(nodeServer, 'listening') 7161cb0ef41Sopenharmony_ci 7171cb0ef41Sopenharmony_ciconsole.log('Node Server listening') 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ciconst nodeServerUndiciClient = new Client(`http://localhost:${nodeServer.address().port}`) 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_ciconst fastifyServer = fastify() 7221cb0ef41Sopenharmony_ci 7231cb0ef41Sopenharmony_cifastifyServer.route({ 7241cb0ef41Sopenharmony_ci url: '/', 7251cb0ef41Sopenharmony_ci method: 'GET', 7261cb0ef41Sopenharmony_ci handler: (request, response) => { 7271cb0ef41Sopenharmony_ci nodeServerUndiciClient.stream({ 7281cb0ef41Sopenharmony_ci path: '/', 7291cb0ef41Sopenharmony_ci method: 'GET', 7301cb0ef41Sopenharmony_ci opaque: response 7311cb0ef41Sopenharmony_ci }, ({ opaque }) => opaque.raw) 7321cb0ef41Sopenharmony_ci } 7331cb0ef41Sopenharmony_ci}) 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ciawait fastifyServer.listen() 7361cb0ef41Sopenharmony_ci 7371cb0ef41Sopenharmony_ciconsole.log('Fastify Server listening') 7381cb0ef41Sopenharmony_ci 7391cb0ef41Sopenharmony_ciconst fastifyServerUndiciClient = new Client(`http://localhost:${fastifyServer.server.address().port}`) 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_citry { 7421cb0ef41Sopenharmony_ci const { statusCode, body } = await fastifyServerUndiciClient.request({ 7431cb0ef41Sopenharmony_ci path: '/', 7441cb0ef41Sopenharmony_ci method: 'GET' 7451cb0ef41Sopenharmony_ci }) 7461cb0ef41Sopenharmony_ci 7471cb0ef41Sopenharmony_ci console.log(`response received ${statusCode}`) 7481cb0ef41Sopenharmony_ci body.setEncoding('utf8') 7491cb0ef41Sopenharmony_ci body.on('data', console.log) 7501cb0ef41Sopenharmony_ci 7511cb0ef41Sopenharmony_ci nodeServerUndiciClient.close() 7521cb0ef41Sopenharmony_ci fastifyServerUndiciClient.close() 7531cb0ef41Sopenharmony_ci fastifyServer.close() 7541cb0ef41Sopenharmony_ci nodeServer.close() 7551cb0ef41Sopenharmony_ci} catch (error) { } 7561cb0ef41Sopenharmony_ci``` 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_ci### `Dispatcher.upgrade(options[, callback])` 7591cb0ef41Sopenharmony_ci 7601cb0ef41Sopenharmony_ciUpgrade 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. 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ciArguments: 7631cb0ef41Sopenharmony_ci 7641cb0ef41Sopenharmony_ci* **options** `UpgradeOptions` 7651cb0ef41Sopenharmony_ci 7661cb0ef41Sopenharmony_ci* **callback** `(error: Error | null, data: UpgradeData) => void` (optional) 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ciReturns: `void | Promise<UpgradeData>` - Only returns a `Promise` if no `callback` argument was passed 7691cb0ef41Sopenharmony_ci 7701cb0ef41Sopenharmony_ci#### Parameter: `UpgradeOptions` 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_ci* **path** `string` 7731cb0ef41Sopenharmony_ci* **method** `string` (optional) - Default: `'GET'` 7741cb0ef41Sopenharmony_ci* **headers** `UndiciHeaders` (optional) - Default: `null` 7751cb0ef41Sopenharmony_ci* **protocol** `string` (optional) - Default: `'Websocket'` - A string of comma separated protocols, in descending preference order. 7761cb0ef41Sopenharmony_ci* **signal** `AbortSignal | EventEmitter | null` (optional) - Default: `null` 7771cb0ef41Sopenharmony_ci 7781cb0ef41Sopenharmony_ci#### Parameter: `UpgradeData` 7791cb0ef41Sopenharmony_ci 7801cb0ef41Sopenharmony_ci* **headers** `http.IncomingHeaders` 7811cb0ef41Sopenharmony_ci* **socket** `stream.Duplex` 7821cb0ef41Sopenharmony_ci* **opaque** `unknown` 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci#### Example 1 - Basic Upgrade Request 7851cb0ef41Sopenharmony_ci 7861cb0ef41Sopenharmony_ci```js 7871cb0ef41Sopenharmony_ciimport { createServer } from 'http' 7881cb0ef41Sopenharmony_ciimport { Client } from 'undici' 7891cb0ef41Sopenharmony_ciimport { once } from 'events' 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_ciconst server = createServer((request, response) => { 7921cb0ef41Sopenharmony_ci response.statusCode = 101 7931cb0ef41Sopenharmony_ci response.setHeader('connection', 'upgrade') 7941cb0ef41Sopenharmony_ci response.setHeader('upgrade', request.headers.upgrade) 7951cb0ef41Sopenharmony_ci response.end() 7961cb0ef41Sopenharmony_ci}).listen() 7971cb0ef41Sopenharmony_ci 7981cb0ef41Sopenharmony_ciawait once(server, 'listening') 7991cb0ef41Sopenharmony_ci 8001cb0ef41Sopenharmony_ciconst client = new Client(`http://localhost:${server.address().port}`) 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_citry { 8031cb0ef41Sopenharmony_ci const { headers, socket } = await client.upgrade({ 8041cb0ef41Sopenharmony_ci path: '/', 8051cb0ef41Sopenharmony_ci }) 8061cb0ef41Sopenharmony_ci socket.on('end', () => { 8071cb0ef41Sopenharmony_ci console.log(`upgrade: ${headers.upgrade}`) // upgrade: Websocket 8081cb0ef41Sopenharmony_ci client.close() 8091cb0ef41Sopenharmony_ci server.close() 8101cb0ef41Sopenharmony_ci }) 8111cb0ef41Sopenharmony_ci socket.end() 8121cb0ef41Sopenharmony_ci} catch (error) { 8131cb0ef41Sopenharmony_ci console.error(error) 8141cb0ef41Sopenharmony_ci client.close() 8151cb0ef41Sopenharmony_ci server.close() 8161cb0ef41Sopenharmony_ci} 8171cb0ef41Sopenharmony_ci``` 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_ci## Instance Events 8201cb0ef41Sopenharmony_ci 8211cb0ef41Sopenharmony_ci### Event: `'connect'` 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_ciParameters: 8241cb0ef41Sopenharmony_ci 8251cb0ef41Sopenharmony_ci* **origin** `URL` 8261cb0ef41Sopenharmony_ci* **targets** `Array<Dispatcher>` 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci### Event: `'disconnect'` 8291cb0ef41Sopenharmony_ci 8301cb0ef41Sopenharmony_ciParameters: 8311cb0ef41Sopenharmony_ci 8321cb0ef41Sopenharmony_ci* **origin** `URL` 8331cb0ef41Sopenharmony_ci* **targets** `Array<Dispatcher>` 8341cb0ef41Sopenharmony_ci* **error** `Error` 8351cb0ef41Sopenharmony_ci 8361cb0ef41Sopenharmony_ci### Event: `'connectionError'` 8371cb0ef41Sopenharmony_ci 8381cb0ef41Sopenharmony_ciParameters: 8391cb0ef41Sopenharmony_ci 8401cb0ef41Sopenharmony_ci* **origin** `URL` 8411cb0ef41Sopenharmony_ci* **targets** `Array<Dispatcher>` 8421cb0ef41Sopenharmony_ci* **error** `Error` 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ciEmitted when dispatcher fails to connect to 8451cb0ef41Sopenharmony_ciorigin. 8461cb0ef41Sopenharmony_ci 8471cb0ef41Sopenharmony_ci### Event: `'drain'` 8481cb0ef41Sopenharmony_ci 8491cb0ef41Sopenharmony_ciParameters: 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_ci* **origin** `URL` 8521cb0ef41Sopenharmony_ci 8531cb0ef41Sopenharmony_ciEmitted when dispatcher is no longer busy. 8541cb0ef41Sopenharmony_ci 8551cb0ef41Sopenharmony_ci## Parameter: `UndiciHeaders` 8561cb0ef41Sopenharmony_ci 8571cb0ef41Sopenharmony_ci* `Record<string, string | string[] | undefined> | string[] | null` 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_ciHeader 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. 8601cb0ef41Sopenharmony_ci 8611cb0ef41Sopenharmony_ciKeys are lowercase and values are not modified. 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_ciResponse headers will derive a `host` from the `url` of the [Client](Client.md#class-client) instance if no `host` header was previously specified. 8641cb0ef41Sopenharmony_ci 8651cb0ef41Sopenharmony_ci### Example 1 - Object 8661cb0ef41Sopenharmony_ci 8671cb0ef41Sopenharmony_ci```js 8681cb0ef41Sopenharmony_ci{ 8691cb0ef41Sopenharmony_ci 'content-length': '123', 8701cb0ef41Sopenharmony_ci 'content-type': 'text/plain', 8711cb0ef41Sopenharmony_ci connection: 'keep-alive', 8721cb0ef41Sopenharmony_ci host: 'mysite.com', 8731cb0ef41Sopenharmony_ci accept: '*/*' 8741cb0ef41Sopenharmony_ci} 8751cb0ef41Sopenharmony_ci``` 8761cb0ef41Sopenharmony_ci 8771cb0ef41Sopenharmony_ci### Example 2 - Array 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ci```js 8801cb0ef41Sopenharmony_ci[ 8811cb0ef41Sopenharmony_ci 'content-length', '123', 8821cb0ef41Sopenharmony_ci 'content-type', 'text/plain', 8831cb0ef41Sopenharmony_ci 'connection', 'keep-alive', 8841cb0ef41Sopenharmony_ci 'host', 'mysite.com', 8851cb0ef41Sopenharmony_ci 'accept', '*/*' 8861cb0ef41Sopenharmony_ci] 8871cb0ef41Sopenharmony_ci``` 888