
Bibliothèque Node.js pour diffuser des fichiers en tant que réponses HTTP avec prise en charge du contenu partiel, des requêtes conditionnelles et des en-têtes de cache configurables. Conçue pour être utilisée dans des frameworks web comme Fastify.
Send est une bibliothèque pour diffuser en continu des fichiers du système de fichiers en réponse HTTP, prenant en charge les réponses partielles (Ranges), la négociation conditionnelle GET (If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since), une couverture de tests élevée et des événements granulaires qui peuvent être exploités pour prendre les mesures appropriées dans votre application ou framework.
Ce module Node.js est disponible via le registre npm. L'installation se fait à l'aide de la commande npm install :
$ npm install @fastify/send
@types/mime@3 doit être utilisé si vous souhaitez utiliser TypeScript ;
@types/mime@4 a supprimé les types mime.
$ npm install -D @types/mime@3
const send = require('@fastify/send')
Fournit statusCode, headers, et stream pour le chemin donné à envoyer à un
res. req est la requête HTTP Node.js et path est un chemin encodé en URL
à envoyer (encodé en URL, pas le chemin réel du système de fichiers).
Active ou désactive l'acceptation des requêtes avec plages, par défaut true.
En désactivant cela, l'en-tête Accept-Ranges ne sera pas envoyé et le contenu
de l'en-tête de requête Range sera ignoré.
Active ou désactive l'en-tête de réponse Cache-Control, par défaut true.
La désactivation de cette option ignore les options immutable et maxAge.
Par défaut, cette bibliothèque utilise le module mime pour définir le Content-Type
de la réponse en fonction de l'extension du fichier demandé.
Pour désactiver cette fonctionnalité, définissez contentType à false.
L'en-tête Content-Type devra être défini manuellement si désactivé.
Définit comment les "dotfiles" sont traités lorsqu'ils sont rencontrés. Un dotfile est un fichier
ou un répertoire qui commence par un point ("."). Notez que cette vérification est effectuée sur
le chemin lui-même sans vérifier si le chemin existe sur le
disque. Si root est spécifié, seuls les dotfiles au-dessus de la racine sont
vérifiés (c'est-à-dire que la racine elle-même peut se trouver dans un dotfile lorsqu'elle est définie
sur "deny").
'allow' Aucun traitement spécial pour les dotfiles.'deny' Envoyer un 403 pour toute requête concernant un dotfile.'ignore' Faire comme si le dotfile n'existait pas et renvoyer 404.La valeur par défaut est similaire à 'ignore', à l'exception que
cette valeur par défaut n'ignorera pas les fichiers dans un répertoire qui commence
par un point, pour des raisons de rétrocompatibilité.
Décalage en octets à la fin du flux, par défaut la longueur du fichier
moins 1. La fin est inclusive dans le flux, ce qui signifie que end: 3 inclura
le 4ème octet dans le flux.
Active ou désactive la génération d'etag, par défaut true.
Si un fichier donné n'existe pas, essayez d'ajouter une des extensions données,
dans l'ordre donné. Par défaut, cette option est désactivée (définie à false). Un
exemple de valeur qui servira des fichiers HTML sans extension : ['html', 'htm'].
Cette option est ignorée si le fichier demandé a déjà une extension.
Active ou désactive la directive immutable dans l'en-tête de réponse Cache-Control,
par défaut false. Si défini à true, l'option maxAge doit également
être spécifiée pour activer la mise en cache. La directive immutable empêchera
les clients compatibles d'effectuer des requêtes conditionnelles pendant la durée de l'option
maxAge pour vérifier si le fichier a changé.
Par défaut, send prend en charge les fichiers "index.html", pour désactiver cela,
définissez false ou pour fournir un nouvel index, passez une chaîne ou un tableau
dans l'ordre préféré.
Active ou désactive l'en-tête Last-Modified, par défaut true. Utilise la valeur
de dernière modification du système de fichiers.
Fournit un âge maximum en millisecondes pour la mise en cache HTTP, par défaut 0. Cela peut aussi être une chaîne acceptée par le module ms.
Spécifie la taille maximale du contenu de la réponse, par défaut la taille totale du fichier.
Cela sera utilisé lorsque acceptRanges est true.
Sert les fichiers relatifs à path.
Décalage en octets au début du flux, par défaut 0. Le début est inclusif,
ce qui signifie que start: 2 inclura le 3ème octet dans le flux.
Lorsqu'elle est fournie, cette option définit le nombre maximum d'octets que le tampon interne conservera avant de suspendre les lectures de la ressource sous-jacente. Si vous omettez cette option (ou passez undefined), Node.js revient à son paramètre par défaut intégré pour les flux binaires lisibles.
L'export mime est l'instance globale du
module npm mime.
Il est utilisé pour configurer les types MIME associés aux extensions de fichiers ainsi que d'autres options pour résoudre le type MIME d'un fichier (comme le type par défaut à utiliser pour une extension de fichier inconnue).
Il n'effectue pas de mise en cache interne, vous devriez utiliser un proxy inverse comme Varnish pour cela, ou ces choses fantaisistes appelées CDN. Si votre application est suffisamment petite pour bénéficier d'une mise en cache mémoire sur un seul nœud, elle est suffisamment petite pour n'avoir pas besoin de mise en cache du tout ;).
Pour activer la sortie de l'instrumentation debug(), exportez NODE_DEBUG :
$ NODE_DEBUG=send node app
$ npm install
$ npm test
Cet exemple simple enverra un fichier spécifique à toutes les requêtes.
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)
Cet exemple simple servira tous les fichiers d'un
répertoire donné au niveau supérieur. Par exemple, une requête
GET /foo.txt renverra /www/public/foo.txt.
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)
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Types inconnus par défaut en text/plain
send.mime.default_type = 'text/plain'
// Ajouter un type personnalisé
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)
Ceci est un exemple de service d'une structure de répertoires avec une fonction personnalisée pour afficher la liste d'un répertoire.
const http = require('node:http')
const fs = require('node:fs')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Transférer des fichiers arbitraires depuis /www/example.com/public/*
// avec un gestionnaire personnalisé pour l'affichage du répertoire
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') {
// obtenir la liste du répertoire
const list = await readdir(metadata.path)
// afficher un index pour le répertoire
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)
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
// transférer des fichiers arbitraires depuis
// /www/example.com/public/*
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
switch (type) {
case 'directory': {
// votre logique personnalisée de gestion des répertoires :
res.writeHead(301, {
'Location': metadata.requestPath + '/'
})
res.end('Redirection vers ' + metadata.requestPath + '/')
break
}
case 'error': {
// votre logique personnalisée de gestion des erreurs :
res.writeHead(metadata.error.status ?? 500, {})
res.end(metadata.error.message)
break
}
default: {
// vos en-têtes personnalisés
// servir tous les fichiers en téléchargement
res.setHeader('Content-Disposition', 'attachment')
res.writeHead(statusCode, headers)
stream.pipe(res)
}
}
})
server.listen(3000)
Sous licence MIT.