Plan Checker (neues Studenten-Werkzeug, Seitenleiste + Admin → Plan-Checker- Merkmale): lädt einen Bauplan als PDF hoch und lässt ChatGPT oder Claude ihn gegen eine gepflegte Merkmalsliste prüfen. PDF-Rendering (pdf.js + @napi-rs/canvas) berücksichtigt jetzt Ebenen (Optional Content Groups) und WASM-Decoder korrekt, sendet eine Übersicht plus mehrere hochaufgelöste Kachel-Ausschnitte statt eines einzelnen, zu groben Bilds, und beide Anbieter bekommen dasselbe Bildmaterial. Jedes Prüfergebnis kann auf eines der gesendeten Bilder als Beleg verweisen (bildIndex) — als Screenshot im Ergebnis anklickbar, öffnet vergrößert in einem Modal statt eines von Chrome blockierten target=_blank-Links auf eine data:-URL. KI-Modellname ist jetzt pro Konto überschreibbar (Einstellungen → Mein Konto) für Drittanbieter mit abweichendem Modell-Katalog. Wochenbericht: dichte Kartenansicht bekommt einen Fokus-Modus — nur der Kommentar liegt offen, Leistungsphasen und Beteiligte stecken in aufklappbaren Abschnitten statt dauerhaft nebeneinander zu stehen. Projektbereich: Terminplan-Auslastung rechnet jetzt exakt wie der Auslastungs-Tab/die Wandtafel (statt einer unabhängigen, tageweisen Schätzung); die LPH-Fortschrittsliste im Dashboard zeigt nur noch die beauftragten Leistungsphasen. Wandtafel: Dashboard-Kopf mit Kennzahlen-Reihe und Panel-Reihe neu strukturiert, in den Blautönen des Firmenlogos; dieselbe Palette wurde anschließend auf den gesamten App-weiten Dark Mode übernommen. Dateibereinigung: nicht mehr benötigte Test-Uploads/Backups entfernt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
534 lines
18 KiB
Markdown
534 lines
18 KiB
Markdown
# Client
|
|
|
|
<!--introduced_in=v1.0.0-->
|
|
|
|
<!--type=module-->
|
|
|
|
<!-- source_link=lib/dispatcher/client.js -->
|
|
|
|
> Stability: 2 - Stable
|
|
|
|
A basic HTTP/1.1 client mapped on top of a single TCP/TLS connection. When the
|
|
server supports HTTP/2 and selects it during ALPN negotiation, the same
|
|
connection is used for HTTP/2. Pipelining is disabled by default.
|
|
|
|
`Client` extends [`Dispatcher`][] and is the lowest-level dispatcher in undici:
|
|
it manages exactly one origin over one connection. For pooling across multiple
|
|
connections use [`Pool`][], and for routing across multiple origins use
|
|
[`Agent`][]. Requests are not guaranteed to be dispatched in the order in which
|
|
they are invoked.
|
|
|
|
```mjs
|
|
import { Client } from 'undici'
|
|
|
|
const client = new Client('http://localhost:3000')
|
|
const { statusCode, body } = await client.request({ path: '/', method: 'GET' })
|
|
```
|
|
|
|
## Class: `Client`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* Extends: {Dispatcher}
|
|
|
|
### `new Client(url[, options])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `url` {URL|string} The origin to connect to. Only the protocol, hostname, and
|
|
port are used.
|
|
* `options` {Object} (optional)
|
|
* `bodyTimeout` {number|null} The timeout, in milliseconds, after which a
|
|
request times out while receiving body data. Monitors the time between
|
|
consecutive body chunks. Use `0` to disable it entirely. **Default:**
|
|
`300e3`.
|
|
* `headersTimeout` {number|null} The timeout, in milliseconds, the parser
|
|
waits to receive the complete HTTP headers before the request times out. Use
|
|
`0` to disable it entirely. **Default:** `300e3`.
|
|
HTTP/1.1 headers/body parser timeouts are not guaranteed to fire with exact
|
|
millisecond precision: delays up to 1000ms use native timers, while larger
|
|
delays use undici's lower-overhead fast timers with a target resolution
|
|
around 500ms.
|
|
* `connectTimeout` {number|null} The timeout, in milliseconds, for
|
|
establishing a socket connection. Use `0` to disable it entirely.
|
|
**Default:** `10e3`.
|
|
* `keepAliveTimeout` {number|null} The timeout, in milliseconds, after which a
|
|
socket with no active requests times out. Monitors the time between activity
|
|
on a connected socket. This value may be overridden by *keep-alive* hints
|
|
from the server. **Default:** `4e3`.
|
|
* `keepAliveMaxTimeout` {number|null} The maximum allowed `keepAliveTimeout`,
|
|
in milliseconds, when overridden by *keep-alive* hints from the server.
|
|
**Default:** `600e3`.
|
|
* `keepAliveTimeoutThreshold` {number|null} A number of milliseconds
|
|
subtracted from server *keep-alive* hints when overriding `keepAliveTimeout`,
|
|
to account for timing inaccuracies caused by e.g. transport latency.
|
|
**Default:** `2e3`.
|
|
* `maxHeaderSize` {number|null} The maximum length of request headers, in
|
|
bytes. **Default:** the value of Node.js' `--max-http-header-size` or
|
|
`16384` (16 KiB).
|
|
* `maxResponseSize` {number|null} The maximum length of a response body, in
|
|
bytes. Set to `-1` to disable it. **Default:** `-1`.
|
|
* `maxRequestsPerClient` {number|null} The maximum number of requests to send
|
|
over a single connection before the socket is reset. Use `0` to disable this
|
|
limit. **Default:** `null`.
|
|
* `localAddress` {string|null} The local IP address the socket should connect
|
|
from. **Default:** `null`.
|
|
* `pipelining` {number|null} The number of concurrent requests sent over the
|
|
single connection, per [RFC 7230, section 6.3.2][]. Only enable values
|
|
greater than `1` when the remote server is trusted. Set to `0` to disable
|
|
keep-alive connections. Has no effect once HTTP/2 is negotiated; see
|
|
`maxConcurrentStreams` for the HTTP/2 dispatch ceiling. **Default:** `1`.
|
|
* `connect` {Object|Function|null} Configures how connections are established.
|
|
Either a `ConnectOptions` object passed to the built-in
|
|
[`buildConnector`][] (every [`tls.connect()`][] option is accepted, plus the
|
|
fields below), or a custom connector function with the signature
|
|
`(options, callback)`. **Default:** `null`.
|
|
* `socketPath` {string|null} An IPC endpoint, either a Unix domain socket or
|
|
a Windows named pipe. **Default:** `null`.
|
|
* `maxCachedSessions` {number|null} The maximum number of cached TLS
|
|
sessions. Use `0` to disable TLS session caching. **Default:** `100`.
|
|
* `timeout` {number|null} The connection timeout, in milliseconds.
|
|
**Default:** `10e3`.
|
|
* `servername` {string|null} The TLS server name used for SNI.
|
|
* `keepAlive` {boolean|null} Whether TCP keep-alive is enabled on the socket.
|
|
**Default:** `true`.
|
|
* `keepAliveInitialDelay` {number|null} The TCP keep-alive interval for the
|
|
socket, in milliseconds. **Default:** `60000`.
|
|
* `strictContentLength` {boolean} Whether to throw when the request
|
|
`content-length` header does not match the length of the request body.
|
|
Disabling this exposes the application to HTTP request smuggling; only do so
|
|
in controlled environments where the request source is fully trusted.
|
|
**Default:** `true`.
|
|
* `autoSelectFamily` {boolean} Enables a family autodetection algorithm that
|
|
loosely implements section 5 of [RFC 8305][]. Ignored if unsupported by the
|
|
current Node.js version. **Default:** `false`.
|
|
* `autoSelectFamilyAttemptTimeout` {number} The time, in milliseconds, to wait
|
|
for a connection attempt to finish before trying the next address when
|
|
`autoSelectFamily` is enabled. **Default:** `250`.
|
|
* `allowH2` {boolean} Enables HTTP/2 support when the server assigns it a
|
|
higher priority through ALPN negotiation. **Default:** `true`.
|
|
* `useH2c` {boolean} _Deprecated: use h2Options.useH2c instead_ Enforces h2c (HTTP/2 cleartext) for non-HTTPS
|
|
connections. **Default:** `false`.
|
|
* `maxConcurrentStreams` {number} _Deprecated: use h2Options.useH2c instead_ The maximum number of concurrent HTTP/2
|
|
streams for a single session. Once h2 is negotiated this — not `pipelining`,
|
|
which is HTTP/1.1 only — is the ceiling used to dispatch in-flight requests.
|
|
It may be overridden by the server's `SETTINGS_MAX_CONCURRENT_STREAMS`
|
|
frame. **Default:** `100`.
|
|
* `connectionWindowSize` {number} _Deprecated: use h2Options.connectionWindowSize instead_ The HTTP/2 connection-level flow-control
|
|
window size set via `ClientHttp2Session.setLocalWindowSize()`. Must be a
|
|
positive integer. **Default:** `524288`.
|
|
* `pingInterval` {number} _Deprecated: use h2Options.pingInterval instead_ The time interval, in milliseconds, between HTTP/2
|
|
PING frames. Set to `0` to disable PING frames. Applies only to HTTP/2
|
|
connections and emits a `ping` event on the client. **Default:** `60e3`.
|
|
* `h2Options` {object} Set of options for HTTP/2 sessions
|
|
* `useH2c` {boolean} Enforces h2c (HTTP/2 cleartext) for non-HTTPS
|
|
connections. **Default:** `false`.
|
|
* `maxConcurrentStreams` {number} The maximum number of concurrent HTTP/2
|
|
streams for a single session. Once h2 is negotiated this — not `pipelining`,
|
|
which is HTTP/1.1 only — is the ceiling used to dispatch in-flight requests.
|
|
It may be overridden by the server's `SETTINGS_MAX_CONCURRENT_STREAMS`
|
|
frame. **Default:** `100`.
|
|
* `connectionWindowSize` {number} The HTTP/2 connection-level flow-control
|
|
window size set via `ClientHttp2Session.setLocalWindowSize()`. Must be a
|
|
positive integer. **Default:** `524288`.
|
|
* `pingInterval` {number} The time interval, in milliseconds, between HTTP/2
|
|
PING frames. Set to `0` to disable PING frames. Applies only to HTTP/2
|
|
connections and emits a `ping` event on the client. **Default:** `60e3`.
|
|
* `settings` {object} `SETTINGS` frame options. For full reference, take a
|
|
look to [HTTP/2#Settings Object](https://nodejs.org/api/http2.html#settings-object)
|
|
* `webSocket` {Object} (optional) WebSocket-specific configuration.
|
|
* `maxFragments` {number} The maximum number of fragments in a message. Set
|
|
to `0` to disable the limit. **Default:** `131072`.
|
|
* `maxPayloadSize` {number} The maximum allowed payload size, in bytes, for
|
|
WebSocket messages. Applied to uncompressed messages, compressed frame
|
|
payloads, and decompressed (`permessage-deflate`) messages. Set to `0` to
|
|
disable the limit. **Default:** `134217728`.
|
|
* `eventSource` {Object} (optional) EventSource-specific configuration.
|
|
* `maxEventSize` {number} The maximum allowed event size, in bytes, for
|
|
EventSource messages. Set to `0` to disable the limit.
|
|
**Default:** `buffer.kStringMaxLength`.
|
|
* Returns: {Client}
|
|
|
|
Instantiating a `Client` does not open a connection; the connection is
|
|
established lazily once a request is queued. Call `client.connect()` to connect
|
|
eagerly.
|
|
|
|
> Notes about HTTP/2:
|
|
>
|
|
> * Pseudo headers (`:path`, `:method`, `:scheme`, `:authority`) are attached
|
|
> automatically and overwrite any user-provided values.
|
|
> * The server must support HTTP/2 and select it during ALPN negotiation, and
|
|
> must not give HTTP/1.1 a higher priority than HTTP/2.
|
|
> * `PUSH` frames are not supported.
|
|
|
|
```mjs displayName="Basic instantiation"
|
|
import { Client } from 'undici'
|
|
|
|
const client = new Client('http://localhost:3000')
|
|
```
|
|
|
|
```mjs displayName="TLS options (object connector)"
|
|
import { Client } from 'undici'
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
const client = new Client('https://localhost:3000', {
|
|
connect: {
|
|
rejectUnauthorized: false,
|
|
ca: readFileSync('./ca-cert.pem')
|
|
}
|
|
})
|
|
```
|
|
|
|
```mjs displayName="Unix domain socket"
|
|
import { Client } from 'undici'
|
|
|
|
const client = new Client('http://localhost:3000', {
|
|
connect: {
|
|
socketPath: '/var/run/docker.sock'
|
|
}
|
|
})
|
|
```
|
|
|
|
```mjs displayName="Custom DNS lookup"
|
|
import { Client } from 'undici'
|
|
import dns from 'node:dns'
|
|
|
|
const client = new Client('https://example.com', {
|
|
connect: {
|
|
lookup (hostname, options, callback) {
|
|
dns.lookup(hostname, { ...options, family: 4 }, callback)
|
|
}
|
|
}
|
|
})
|
|
```
|
|
|
|
```mjs displayName="Custom connector (function)"
|
|
import { Client, buildConnector } from 'undici'
|
|
|
|
const connector = buildConnector({ rejectUnauthorized: false })
|
|
const client = new Client('https://localhost:3000', {
|
|
connect (opts, cb) {
|
|
connector(opts, (err, socket) => {
|
|
if (err) {
|
|
cb(err)
|
|
} else {
|
|
cb(null, socket)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
```
|
|
|
|
When a connector function is provided, undici wraps it to automatically inject
|
|
`socketPath` and `allowH2` into the `options` argument when those values are set
|
|
on the client. See [`Connector`][] for details on building custom connectors.
|
|
|
|
### `client.close([callback])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
Implements [`dispatcher.close([callback])`][]. Closes the client gracefully,
|
|
waiting for enqueued requests to complete before resolving.
|
|
|
|
### `client.destroy([error[, callback]])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
Implements [`dispatcher.destroy([error[, callback]])`][]. Destroys the client
|
|
abruptly, aborting all pending and running requests, and waits until the socket
|
|
is closed before invoking `callback` (or resolving the returned promise).
|
|
|
|
### `client.connect(options[, callback])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `options` {Object} The connect options, identical to
|
|
[`dispatcher.connect()`][] except that `origin` is omitted because the client
|
|
is bound to a single origin.
|
|
* `callback` {Function} (optional)
|
|
* Returns: {Promise|void} A promise when `callback` is not provided.
|
|
|
|
Starts a connection to the client's origin and tunnels a connection through it,
|
|
as defined by [`dispatcher.connect()`][].
|
|
|
|
### `client.dispatch(options, handlers)`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
Implements [`dispatcher.dispatch(options, handler)`][]. This is the lowest-level
|
|
API used by all other request methods; prefer `client.request()` for most use
|
|
cases.
|
|
|
|
### `client.pipeline(options, handler)`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
See [`dispatcher.pipeline(options, handler)`][]. Sends a request and returns a
|
|
{Duplex} stream that the request body is written to and the response body is
|
|
read from.
|
|
|
|
### `client.request(options[, callback])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `options` {Object}
|
|
* `callback` {Function} (optional)
|
|
* Returns: {Promise|void} A promise resolving to the response data when
|
|
`callback` is not provided.
|
|
|
|
See [`dispatcher.request(options[, callback])`][]. Performs an HTTP request and
|
|
returns its status code, headers, trailers, and a readable body stream.
|
|
|
|
```mjs
|
|
import { Client } from 'undici'
|
|
|
|
const client = new Client('http://localhost:3000')
|
|
const { statusCode, headers, body } = await client.request({
|
|
path: '/',
|
|
method: 'GET'
|
|
})
|
|
|
|
console.log(statusCode)
|
|
for await (const chunk of body) {
|
|
console.log(chunk.toString())
|
|
}
|
|
```
|
|
|
|
### `client.stream(options, factory[, callback])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `options` {Object}
|
|
* `factory` {Function} Returns a {Writable} the response body is piped into.
|
|
* `callback` {Function} (optional)
|
|
* Returns: {Promise|void} A promise when `callback` is not provided.
|
|
|
|
See [`dispatcher.stream(options, factory[, callback])`][]. A faster alternative
|
|
to `client.request()` when the destination of the response body is known in
|
|
advance.
|
|
|
|
### `client.upgrade(options[, callback])`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `options` {Object}
|
|
* `callback` {Function} (optional)
|
|
* Returns: {Promise|void} A promise when `callback` is not provided.
|
|
|
|
See [`dispatcher.upgrade(options[, callback])`][]. Upgrades a connection to a
|
|
different protocol, such as for WebSocket or HTTP `CONNECT`.
|
|
|
|
### `client.closed`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* Type: {boolean}
|
|
|
|
`true` after `client.close()` has been called.
|
|
|
|
### `client.destroyed`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* Type: {boolean}
|
|
|
|
`true` after `client.destroy()` has been called, or after `client.close()` has
|
|
been called and the client shutdown has completed.
|
|
|
|
### `client.pipelining`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* Type: {number}
|
|
|
|
The pipelining factor. This property can be read and written to adjust the
|
|
number of concurrent requests sent over the connection. Only enable pipelining
|
|
with trusted remote servers.
|
|
|
|
### `client.stats`
|
|
|
|
<!-- YAML
|
|
added: v7.9.0
|
|
-->
|
|
|
|
* Type: {ClientStats}
|
|
|
|
Aggregate statistics for the client. See [`ClientStats`][].
|
|
|
|
### Event: `'connect'`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `origin` {URL}
|
|
* `targets` {Array<Dispatcher>}
|
|
|
|
Emitted when a socket has been created and connected. The client connects once
|
|
`client.size > 0`. See [`Dispatcher` Event: `'connect'`][].
|
|
|
|
```mjs
|
|
import { createServer } from 'node:http'
|
|
import { Client } from 'undici'
|
|
import { once } from 'node:events'
|
|
|
|
const server = createServer((request, response) => {
|
|
response.end('Hello, World!')
|
|
}).listen()
|
|
|
|
await once(server, 'listening')
|
|
|
|
const client = new Client(`http://localhost:${server.address().port}`)
|
|
|
|
client.on('connect', (origin) => {
|
|
console.log(`Connected to ${origin}`)
|
|
})
|
|
|
|
const { body } = await client.request({ path: '/', method: 'GET' })
|
|
body.setEncoding('utf8')
|
|
body.on('data', console.log)
|
|
|
|
client.close()
|
|
server.close()
|
|
```
|
|
|
|
### Event: `'disconnect'`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
changes:
|
|
- version: v4.0.0
|
|
pr-url: https://github.com/nodejs/undici/pull/771
|
|
description: The event is only emitted if the client had previously
|
|
connected.
|
|
-->
|
|
|
|
* `origin` {URL}
|
|
* `targets` {Array<Dispatcher>}
|
|
* `error` {Error}
|
|
|
|
Emitted when a socket has disconnected. The `error` argument is the error that
|
|
caused the disconnection. The client reconnects if or once `client.size > 0`.
|
|
See [`Dispatcher` Event: `'disconnect'`][].
|
|
|
|
```mjs
|
|
import { createServer } from 'node:http'
|
|
import { Client } from 'undici'
|
|
import { once } from 'node:events'
|
|
|
|
const server = createServer((request, response) => {
|
|
response.destroy()
|
|
}).listen()
|
|
|
|
await once(server, 'listening')
|
|
|
|
const client = new Client(`http://localhost:${server.address().port}`)
|
|
|
|
client.on('disconnect', (origin) => {
|
|
console.log(`Disconnected from ${origin}`)
|
|
})
|
|
|
|
try {
|
|
await client.request({ path: '/', method: 'GET' })
|
|
} catch (error) {
|
|
console.error(error.message)
|
|
} finally {
|
|
client.close()
|
|
server.close()
|
|
}
|
|
```
|
|
|
|
### Event: `'drain'`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `origin` {URL}
|
|
|
|
Emitted when the pipeline is no longer busy. See
|
|
[`Dispatcher` Event: `'drain'`][].
|
|
|
|
```mjs
|
|
import { createServer } from 'node:http'
|
|
import { Client } from 'undici'
|
|
import { once } from 'node:events'
|
|
|
|
const server = createServer((request, response) => {
|
|
response.end('Hello, World!')
|
|
}).listen()
|
|
|
|
await once(server, 'listening')
|
|
|
|
const client = new Client(`http://localhost:${server.address().port}`)
|
|
|
|
client.on('drain', () => {
|
|
console.log('drain event')
|
|
client.close()
|
|
server.close()
|
|
})
|
|
|
|
await Promise.all([
|
|
client.request({ path: '/', method: 'GET' }),
|
|
client.request({ path: '/', method: 'GET' }),
|
|
client.request({ path: '/', method: 'GET' })
|
|
])
|
|
```
|
|
|
|
### Event: `'error'`
|
|
|
|
<!-- YAML
|
|
added: v1.0.0
|
|
-->
|
|
|
|
* `error` {Error}
|
|
|
|
Emitted for user errors, such as throwing inside an `onResponseError` handler.
|
|
|
|
[RFC 7230, section 6.3.2]: https://tools.ietf.org/html/rfc7230#section-6.3.2
|
|
[RFC 8305]: https://tools.ietf.org/html/rfc8305#section-5
|
|
[`Agent`]: Agent.md#class-agent
|
|
[`ClientStats`]: ClientStats.md
|
|
[`Connector`]: Connector.md
|
|
[`Dispatcher` Event: `'connect'`]: Dispatcher.md#event-connect
|
|
[`Dispatcher` Event: `'disconnect'`]: Dispatcher.md#event-disconnect
|
|
[`Dispatcher` Event: `'drain'`]: Dispatcher.md#event-drain
|
|
[`Dispatcher`]: Dispatcher.md#class-dispatcher
|
|
[`Pool`]: Pool.md#class-pool
|
|
[`buildConnector`]: Connector.md
|
|
[`dispatcher.close([callback])`]: Dispatcher.md#dispatcherclosecallback
|
|
[`dispatcher.connect()`]: Dispatcher.md#dispatcherconnectoptions-callback
|
|
[`dispatcher.destroy([error[, callback]])`]: Dispatcher.md#dispatcherdestroyerror-callback
|
|
[`dispatcher.dispatch(options, handler)`]: Dispatcher.md#dispatcherdispatchoptions-handler
|
|
[`dispatcher.pipeline(options, handler)`]: Dispatcher.md#dispatcherpipelineoptions-handler
|
|
[`dispatcher.request(options[, callback])`]: Dispatcher.md#dispatcherrequestoptions-callback
|
|
[`dispatcher.stream(options, factory[, callback])`]: Dispatcher.md#dispatcherstreamoptions-factory-callback
|
|
[`dispatcher.upgrade(options[, callback])`]: Dispatcher.md#dispatcherupgradeoptions-callback
|
|
[`tls.connect()`]: https://nodejs.org/api/tls.html#tlsconnectoptions-callback
|