
Libreria Node.js per lo streaming di file come risposte HTTP con supporto per contenuto parziale, richieste condizionali e intestazioni di cache configurabili. Progettata per l'uso in framework web come 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 è una libreria per lo streaming di file dal file system come risposta HTTP,
che supporta risposte parziali (Ranges), negoziazione conditional-GET (If-Match,
If-Unmodified-Since, If-None-Match, If-Modified-Since), un'elevata copertura dei test
e eventi granulari che possono essere sfruttati per intraprendere azioni appropriate nella tua
applicazione o framework.
## Installazione
Questo è un modulo [Node.js](https://nodejs.org/en/) disponibile tramite il
[npm registry](https://www.npmjs.com/). L'installazione viene effettuata utilizzando il
[comando `npm install`](https://docs.npmjs.com/downloading-and-installing-packages-locally):
```bash
$ npm install @fastify/send
```
### TypeScript
`@types/mime@3` deve essere utilizzato se si desidera usare TypeScript;
`@types/mime@4` ha rimosso i tipi `mime`.
```bash
$ npm install -D @types/mime@3
```
## API
```js
const send = require('@fastify/send')
```
### send(req, path, [options])
Fornisce `statusCode`, `headers` e `stream` per il percorso specificato da inviare a un
`res`. Il parametro `req` è la richiesta HTTP di Node.js e `path` è un percorso codificato in URL
da inviare (codificato in URL, non il percorso effettivo del file system).
#### Opzioni
##### acceptRanges
Abilita o disabilita l'accettazione di richieste ranged, il valore predefinito è true.
Disabilitandola non verrà inviato `Accept-Ranges` e verrà ignorato il contenuto
dell'header di richiesta `Range`.
##### cacheControl
Abilita o disabilita l'impostazione dell'header di risposta `Cache-Control`, il valore predefinito è
true. Disabilitandola verranno ignorate le opzioni `immutable` e `maxAge`.
##### contentType
Per impostazione predefinita, questa libreria utilizza il modulo `mime` per impostare il `Content-Type`
della risposta in base all'estensione del file richiesto.
Per disabilitare questa funzionalità, impostare `contentType` su `false`.
Se disabilitata, l'header `Content-Type` dovrà essere impostato manualmente.
##### dotfiles
Imposta come vengono trattati i "dotfile" quando vengono incontrati. Un dotfile è un file
o una directory che inizia con un punto ("."). Si noti che questo controllo viene effettuato sul
percorso stesso senza verificare se il percorso esiste sul
disco. Se `root` è specificato, vengono controllati solo i dotfile al di sopra della root
(ovvero la root stessa può trovarsi all'interno di un dotfile quando impostato
su "deny").
- `'allow'` Nessun trattamento speciale per i dotfile.
- `'deny'` Invia un 403 per qualsiasi richiesta di un dotfile.
- `'ignore'` Finge che il dotfile non esista e restituisce 404.
Il valore predefinito è _simile_ a `'ignore'`, con l'eccezione che
questo valore predefinito non ignorerà i file all'interno di una directory che inizia
con un punto, per retrocompatibilità.
##### end
Offset in byte in cui termina lo stream, il valore predefinito è la lunghezza del file
meno 1. La fine è inclusiva nello stream, il che significa che `end: 3` includerà
il 4° byte nello stream.
##### etag
Abilita o disabilita la generazione dell'etag, il valore predefinito è true.
##### extensions
Se un determinato file non esiste, prova ad aggiungere una delle estensioni fornite,
nell'ordine indicato. Per impostazione predefinita, questa opzione è disabilitata (impostata su `false`). Un
valore di esempio che servirà file HTML senza estensione: `['html', 'htm']`.
Questa opzione viene saltata se il file richiesto ha già un'estensione.
##### immutable
Abilita o disabilita la direttiva `immutable` nell'header di risposta `Cache-Control`,
il valore predefinito è `false`. Se impostata su `true`, dovrebbe essere specificata anche l'opzione `maxAge`
per abilitare la cache. La direttiva `immutable` impedirà
ai client supportati di effettuare richieste condizionali durante la durata dell'opzione
`maxAge` per verificare se il file è cambiato.
##### index
Per impostazione predefinita send supporta i file "index.html", per disabilitare questa funzionalità
impostare `false` oppure, per fornire un nuovo indice, passare una stringa o un array
nell'ordine preferito.
##### lastModified
Abilita o disabilita l'header `Last-Modified`, il valore predefinito è true. Utilizza il valore
di ultima modifica del file system.
##### maxAge
Fornisce un max-age in millisecondi per la cache HTTP, il valore predefinito è 0.
Può anche essere una stringa accettata dal
modulo [ms](https://www.npmjs.com/package/ms).
##### maxContentRangeChunkSize
Specifica la dimensione massima del contenuto della risposta, il valore predefinito è l'intera dimensione del file.
Verrà utilizzato quando `acceptRanges` è true.
##### onFile
Viene chiamato con il percorso assoluto del file finale selezionato e le statistiche del file system
dopo la risoluzione del file, ma prima dell'elaborazione della risposta e della creazione dello stream del file.
Il callback può essere sincrono o restituire una promise. Se restituisce una promise,
`send` attende che venga risolta. Se il callback genera un'eccezione o la promise restituita
viene rifiutata, l'operazione viene interrotta e `send()` viene rifiutata.
##### root
Serve i file relativamente a `path`.
##### start
Offset in byte in cui inizia lo stream, il valore predefinito è 0. L'inizio è inclusivo,
il che significa che `start: 2` includerà il 3° byte nello stream.
##### highWaterMark
Quando fornita, questa opzione imposta il numero massimo di byte che il buffer
interno conterrà prima di sospendere le letture dalla risorsa sottostante.
Se si omette questa opzione (o si passa undefined), Node.js ricade sul
suo valore predefinito integrato per gli stream binari leggibili.
### .mime
L'export `mime` è l'istanza globale del
[modulo npm `mime`](https://www.npmjs.com/package/mime).
Viene utilizzato per configurare i tipi MIME associati alle estensioni dei file
nonché altre opzioni su come risolvere il tipo MIME di un file (come il
tipo predefinito da usare per un'estensione di file sconosciuta).
## Caching
_Non_ esegue caching interno; per questo dovresti usare una cache di reverse proxy
come Varnish, o quelle cose sofisticate chiamate CDN. Se la tua
applicazione è abbastanza piccola da trarre vantaggio dalla cache in memoria
su singolo nodo, è abbastanza piccola da non aver affatto bisogno di caching ;).
## Debugging
Per abilitare l'output di strumentazione di `debug()` esporta __NODE_DEBUG__:
```
$ NODE_DEBUG=send node app
```
## Esecuzione dei test
```
$ npm install
$ npm test
```
## Esempi
### Servire un file specifico
Questo semplice esempio invierà un file specifico a tutte le richieste.
```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)
```
### Servire tutti i file da una directory
Questo semplice esempio servirà tutti i file in una
determinata directory come livello superiore. Ad esempio, una richiesta
`GET /foo.txt` restituirà `/www/public/foo.txt`.
```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)
```
### Tipi di file personalizzati
```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)
```
### Vista personalizzata dell'indice delle directory
Questo è un esempio di pubblicazione di una struttura di directory con una
funzione personalizzata per generare un elenco di una directory.
```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)
```
### Servire da una directory root con gestione personalizzata degli errori
```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)
```
## Licenza
Concesso in licenza secondo [MIT](https://github.com/fastify/send/blob/main/LICENSE).