
Node.js-Bibliothek zum Streamen von Dateien als HTTP-Antworten mit Unterstützung für Teilinhalte, bedingte Anfragen und konfigurierbare Cache-Header. Entwickelt für den Einsatz in Web-Frameworks wie Fastify.
# @fastify/send
[](https://github.com/fastify/send/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@fastify/send)
[](https://github.com/neostandard/neostandard)
Send ist eine Bibliothek zum Streamen von Dateien aus dem Dateisystem als HTTP-Antwort
mit Unterstützung für partielle Antworten (Ranges), Conditional-GET-Aushandlung (If-Match,
If-Unmodified-Since, If-None-Match, If-Modified-Since), hoher Testabdeckung
und granularen Events, die genutzt werden können, um geeignete Maßnahmen in Ihrer
Anwendung oder Ihrem Framework zu ergreifen.
## Installation
Dies ist ein [Node.js](https://nodejs.org/en/)-Modul, das über die
[npm registry](https://www.npmjs.com/) verfügbar ist. Die Installation erfolgt mit dem
[`npm install`-Befehl](https://docs.npmjs.com/downloading-and-installing-packages-locally):
```bash
$ npm install @fastify/send
```
### TypeScript
`@types/mime@3` muss verwendet werden, wenn TypeScript genutzt werden soll;
`@types/mime@4` hat die `mime`-Typen entfernt.
```bash
$ npm install -D @types/mime@3
```
## API
```js
const send = require('@fastify/send')
```
### send(req, path, [options])
Stellt `statusCode`, `headers` und `stream` für den angegebenen Pfad bereit, um sie an eine
`res` zu senden. Die `req` ist die Node.js-HTTP-Anfrage und der `path` ist ein urlencodierter Pfad
zum Senden (urlencoded, nicht der tatsächliche Dateisystempfad).
#### Optionen
##### acceptRanges
Aktiviert oder deaktiviert das Akzeptieren von Bereichsanfragen, Standard ist true.
Bei Deaktivierung wird `Accept-Ranges` nicht gesendet und der Inhalt
des `Range`-Anfrage-Headers ignoriert.
##### cacheControl
Aktiviert oder deaktiviert das Setzen des `Cache-Control`-Antwort-Headers, Standard ist
true. Bei Deaktivierung werden die Optionen `immutable` und `maxAge` ignoriert.
##### contentType
Standardmäßig verwendet diese Bibliothek das `mime`-Modul, um den `Content-Type`
der Antwort basierend auf der Dateiendung der angeforderten Datei zu setzen.
Um diese Funktionalität zu deaktivieren, setzen Sie `contentType` auf `false`.
Der `Content-Type`-Header muss dann manuell gesetzt werden.
##### dotfiles
Legt fest, wie mit "Dotfiles" umgegangen wird, wenn sie auftreten. Ein Dotfile ist eine Datei
oder ein Verzeichnis, das mit einem Punkt (".") beginnt. Beachten Sie, dass diese Prüfung auf
dem Pfad selbst erfolgt, ohne zu prüfen, ob der Pfad auf der
Festplatte existiert. Wenn `root` angegeben ist, werden nur die Dotfiles oberhalb des Root
geprüft (d. h. der Root selbst kann sich innerhalb eines Dotfiles befinden, wenn
"deny" gesetzt ist).
- `'allow'` Keine besondere Behandlung für Dotfiles.
- `'deny'` Sendet ein 403 für jede Anfrage nach einem Dotfile.
- `'ignore'` Tut so, als ob das Dotfile nicht existiert, und sendet 404.
Der Standardwert ist _ähnlich_ zu `'ignore'`, mit der Ausnahme, dass
dieser Standard die Dateien innerhalb eines Verzeichnisses, das mit
einem Punkt beginnt, aus Gründen der Abwärtskompatibilität nicht ignoriert.
##### end
Byte-Offset, an dem der Stream endet, Standard ist die Länge der Datei
minus 1. Das Ende ist inklusiv im Stream, das heißt `end: 3` schließt
das 4. Byte im Stream ein.
##### etag
Aktiviert oder deaktiviert die etag-Generierung, Standard ist true.
##### extensions
Wenn eine angegebene Datei nicht existiert, wird versucht, eine der angegebenen Erweiterungen
in der angegebenen Reihenfolge anzuhängen. Standardmäßig ist dies deaktiviert (auf `false` gesetzt). Ein
Beispielwert, der Dateien ohne Erweiterung als HTML ausliefert: `['html', 'htm']`.
Dies wird übersprungen, wenn die angeforderte Datei bereits eine Erweiterung hat.
##### immutable
Aktiviert oder deaktiviert die `immutable`-Direktive im `Cache-Control`-Antwort-
Header, Standard ist `false`. Wenn auf `true` gesetzt, sollte auch die `maxAge`-Option
angegeben werden, um Caching zu ermöglichen. Die `immutable`-Direktive verhindert,
dass unterstützte Clients während der Laufzeit der
`maxAge`-Option bedingte Anfragen stellen, um zu prüfen, ob sich die Datei geändert hat.
##### index
Standardmäßig unterstützt send "index.html"-Dateien; um dies zu deaktivieren,
setzen Sie `false`, oder um einen neuen Index anzugeben, übergeben Sie einen String oder ein Array
in der bevorzugten Reihenfolge.
##### lastModified
Aktiviert oder deaktiviert den `Last-Modified`-Header, Standard ist true. Verwendet den
zuletzt geänderten Wert des Dateisystems.
##### maxAge
Gibt eine max-age in Millisekunden für HTTP-Caching an, Standard ist 0.
Dies kann auch ein String sein, der vom
[ms](https://www.npmjs.com/package/ms)-Modul akzeptiert wird.
##### maxContentRangeChunkSize
Gibt die maximale Größe des Antwortinhalts an, Standard ist die gesamte Dateigröße.
Dies wird verwendet, wenn `acceptRanges` true ist.
##### onFile
Wird mit dem absoluten Pfad der letztendlich ausgewählten Datei und den Dateisystem-Statistiken
nach der Dateiauflösung aufgerufen, aber vor der Antwortverarbeitung und der Erstellung des Dateistreams.
Der Callback kann synchron sein oder ein Promise zurückgeben. Wenn er ein Promise zurückgibt,
wartet `send` auf dessen Abschluss. Wenn der Callback eine Ausnahme wirft oder sein zurückgegebenes Promise
abgelehnt wird, wird der Vorgang abgebrochen und `send()` wird abgelehnt.
##### root
Liefert Dateien relativ zu `path` aus.
##### start
Byte-Offset, an dem der Stream beginnt, Standard ist 0. Der Start ist inklusiv,
das heißt `start: 2` schließt das 3. Byte im Stream ein.
##### highWaterMark
Wenn angegeben, legt diese Option die maximale Anzahl von Bytes fest, die der interne
Puffer hält, bevor das Lesen aus der zugrunde liegenden Ressource pausiert wird.
Wenn Sie diese Option weglassen (oder undefined übergeben), greift Node.js auf
seinen integrierten Standard für lesbare Binärstreams zurück.
### .mime
Der `mime`-Export ist die globale Instanz des
[`mime`-npm-Moduls](https://www.npmjs.com/package/mime).
Dies wird verwendet, um die MIME-Typen zu konfigurieren, die Dateiendungen
zugeordnet sind, sowie andere Optionen dafür, wie der MIME-Typ einer Datei
aufgelöst wird (wie der Standardtyp, der für eine unbekannte Dateiendung
verwendet wird).
## Caching
Es führt _kein_ internes Caching durch; Sie sollten hierfür einen
Reverse-Proxy-Cache wie Varnish verwenden oder diese schicken Dinger namens
CDNs. Wenn Ihre Anwendung klein genug ist, dass sie von einem
Single-Node-Memory-Caching profitieren würde, ist sie klein genug, dass sie
überhaupt kein Caching benötigt ;).
## Debugging
Um die Ausgabe der `debug()`-Instrumentierung zu aktivieren, exportieren Sie __NODE_DEBUG__:
```
$ NODE_DEBUG=send node app
```
## Tests ausführen
```
$ npm install
$ npm test
```
## Beispiele
### Eine bestimmte Datei bereitstellen
Dieses einfache Beispiel sendet eine bestimmte Datei an alle Anfragen.
```js
const http = require('node:http')
const send = require('send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, '/path/to/index.html')
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
```
### Alle Dateien aus einem Verzeichnis bereitstellen
Dieses einfache Beispiel stellt einfach alle Dateien in einem
gegebenen Verzeichnis als oberste Ebene bereit. Zum Beispiel wird eine Anfrage
`GET /foo.txt` die Datei `/www/public/foo.txt` zurücksenden.
```js
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
```
### Benutzerdefinierte Dateitypen
```js
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Default unknown types to text/plain
send.mime.default_type = 'text/plain'
// Add a custom type
send.mime.define({
'application/x-my-type': ['x-mt', 'x-mtt']
})
const server = http.createServer(function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
```
### Benutzerdefinierte Verzeichnisindex-Ansicht
Dies ist ein Beispiel für das Bereitstellen einer Verzeichnisstruktur mit
einer benutzerdefinierten Funktion zum Rendern einer Auflistung eines Verzeichnisses.
```js
const http = require('node:http')
const fs = require('node:fs')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Transfer arbitrary files from within /www/example.com/public/*
// with a custom handler for directory listing
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { index: false, root: '/www/public' })
if(type === 'directory') {
// get directory list
const list = await readdir(metadata.path)
// render an index for the directory
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end(list.join('\n') + '\n')
} else {
res.writeHead(statusCode, headers)
stream.pipe(res)
}
})
server.listen(3000)
```
### Bereitstellung aus einem Stammverzeichnis mit benutzerdefinierter Fehlerbehandlung
```js
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
// transfer arbitrary files from within
// /www/example.com/public/*
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
switch (type) {
case 'directory': {
// your custom directory handling logic:
res.writeHead(301, {
'Location': metadata.requestPath + '/'
})
res.end('Redirecting to ' + metadata.requestPath + '/')
break
}
case 'error': {
// your custom error-handling logic:
res.writeHead(metadata.error.status ?? 500, {})
res.end(metadata.error.message)
break
}
default: {
// your custom headers
// serve all files for download
res.setHeader('Content-Disposition', 'attachment')
res.writeHead(statusCode, headers)
stream.pipe(res)
}
}
})
server.listen(3000)
```
## Lizenz
Lizenziert unter [MIT](https://github.com/fastify/send/blob/main/LICENSE).