Maison > Article > interface Web > Explication détaillée de l'instance de serveur de fichiers statiques de nœud
Cet article vous présente principalement un exemple pratique de serveur de fichiers statiques de nœud. Cet article listera d'abord ses fonctions puis le partagera avec vous sous forme de code.
Fonctions prises en charge :
Lire les fichiers statiques
L'accès au répertoire peut automatiquement trouver le fichier index.html suivant, si S'il n'y a pas d'index.html, listez les fichiers
Prise en charge du type MIME
Prise en charge/contrôle du cache
Prise en charge de la compression gzip
Prise en charge de la plage, reprise du point d'arrêt
Exécution globale des commandes
Sous-processus en cours d'exécution
1. Créez un service pour lire les fichiers statiques
Introduisez d'abord le module http, créez un serveur et écoutez le port de configuration :
const http = require('http'); const server = http.createServer(); // 监听请求 server.on('request', request.bind(this)); server.listen(config.port, () => { console.log(`静态文件服务启动成功, 访问localhost:${config.port}`); });
Écrivez un fn spécifiquement pour gérer les requêtes et renvoyer les fichiers statiques. Le module url obtient le chemin :
const url = require('url'); const fs = require('fs'); function request(req, res) { const { pathname } = url.parse(req.url); // 访问路径 const filepath = path.join(config.root, pathname); // 文件路径 fs.createReadStream(filepath).pipe(res); // 读取文件,并响应 }
Prend en charge la recherche d'index.html :
if (pathname === '/') { const rootPath = path.join(config.root, 'index.html'); try{ const indexStat = fs.statSync(rootPath); if (indexStat) { filepath = rootPath; } } catch(e) { } }
Lors de l'accès au répertoire, listez les fichiers Répertoire :
fs.stat(filepath, (err, stats) => { if (err) { res.end('not found'); return; } if (stats.isDirectory()) { let files = fs.readdirSync(filepath); files = files.map(file => ({ name: file, url: path.join(pathname, file) })); let html = this.list()({ title: pathname, files }); res.setHeader('Content-Type', 'text/html'); res.end(html); } }
Modèle HTML :
function list() { let tmpl = fs.readFileSync(path.resolve(__dirname, 'template', 'list.html'), 'utf8'); return handlebars.compile(tmpl); }
76c82f278ac045591c9159d381de2c57 9fd01892b579bba0c343404bcccd70fb 93f0f5c25f18dab9d176bd4f6de5d30e a80eb7cbb6fff8b0ff70bae37074b813 8f6d5a544bbc0d98e0f297ef053f784d ef0e6bda9678de73355aeb4407692a87 b2386ffb911b14667cb8f0f91ea547a7{{title}}6e916e0f7d1e588d4f442bf645aedb2f 9c3bca370b5104690d9ef395f2c5f8d1 6c04bd5ca3fcae76e30b72ad730ca86d 4a249f0d628e2318394fd9b75b4636b1hope-server静态文件服务器473f0a7621bec819994bb5020d29372a ff6d136ddc5fdfeffaf53ff6ee95f185 {{#each files}} 25edfb22a4f469ecb59f1190150159c6 0e8c1c10a7257f38575c59bd16d77a1a{{name}}5db79b134e9f6b82c0b36e0489ee08ed bed06894275b65c1ab86501b08a632eb {{/each}} 929d1f5ca49e04fdcb27f9465b944689 36cc49f0c466276486e50c850b7e4956 73a6ac4ed44ffec12cee46588e518a5e
2. Prise en charge du type MIME
Utilisez le module MIME pour obtenez le type de fichier et définissez l'encodage :
res.setHeader('Content-Type', mime.getType(filepath) + ';charset=utf-8');
3. Prise en charge du cache
Cache du protocole http :
Cache-Control : contenu http1.1, indique le client. comment mettre en cache les données et les règles
le client privé peut mettre en cache
le client public et le serveur proxy peuvent mettre en cache
max-age=60 Le contenu mis en cache expirera après 60 secondes
no-cache Vous devez utiliser le cache de comparaison pour vérifier les données et forcer le serveur source à vérifiez à nouveau
non - Tout le contenu du magasin ne sera pas mis en cache, et ni la mise en cache forcée ni la mise en cache de comparaison ne se déclencheront
Expire : http1 .0, cache-control le remplacera et indiquera au client quand le cache expirera
ETag : la valeur de hachage du contenu ajoutera if-none-match dans l'en-tête de la prochaine demande du client : etag value
Last-Modified : L'heure de la dernière modification pour la prochaine demande du client. Ajoutez if-modified-since : Last-Modified dans l'en-tête
handleCache(req, res, stats, hash) { // 当资源过期时, 客户端发现上一次请求资源,服务器有发送Last-Modified, 则再次请求时带上if-modified-since const ifModifiedSince = req.headers['if-modified-since']; // 服务器发送了etag,客户端再次请求时用If-None-Match字段来询问是否过期 const ifNoneMatch = req.headers['if-none-match']; // http1.1内容 max-age=30 为强行缓存30秒 30秒内再次请求则用缓存 private 仅客户端缓存,代理服务器不可缓存 res.setHeader('Cache-Control', 'private,max-age=30'); // http1.0内容 作用与Cache-Control一致 告诉客户端什么时间,资源过期 优先级低于Cache-Control res.setHeader('Expires', new Date(Date.now() + 30 * 1000).toGMTString()); // 设置ETag 根据内容生成的hash res.setHeader('ETag', hash); // 设置Last-Modified 文件最后修改时间 const lastModified = stats.ctime.toGMTString(); res.setHeader('Last-Modified', lastModified); // 判断ETag是否过期 if (ifNoneMatch && ifNoneMatch != hash) { return false; } // 判断文件最后修改时间 if (ifModifiedSince && ifModifiedSince != lastModified) { return false; } // 如果存在且相等,走缓存304 if (ifNoneMatch || ifModifiedSince) { res.writeHead(304); res.end(); return true; } else { return false; } }
4. >
Le client envoie du contenu et indique au support du serveur via Accept-Encoding : gzip, deflate dans l'en-tête de la requête. Quels formats de compression, le serveur compresse le contenu en fonction des formats de compression pris en charge. Si le serveur ne le prend pas en charge, aucune compression ne sera effectuée.getEncoding(req, res) { const acceptEncoding = req.headers['accept-encoding']; // gzip和deflate压缩 if (/\bgzip\b/.test(acceptEncoding)) { res.setHeader('Content-Encoding', 'gzip'); return zlib.createGzip(); } else if (/\bdeflate\b/.test(acceptEncoding)) { res.setHeader('Content-Encoding', 'deflate'); return zlib.createDeflate(); } else { return null; } }5. Reprise du point d'arrêt Le serveur utilise Range : bytes=0-xxx dans l'en-tête de la requête pour déterminer s'il effectue une requête Range si cette valeur existe et est valide. , puis seule la partie demandée du contenu du fichier est renvoyée, le code d'état de la réponse devient 206, indiquant le contenu partiel, et Content-Range est défini. S'il n'est pas valide, un code d'état 416 est renvoyé, indiquant que la plage de demande n'est pas satisfaisante. Si l’en-tête de requête Range n’est pas inclus, continuez à répondre de la manière habituelle.
getStream(req, res, filepath, statObj) { let start = 0; let end = statObj.size - 1; const range = req.headers['range']; if (range) { res.setHeader('Accept-Range', 'bytes'); res.statusCode = 206;//返回整个内容的一块 let result = range.match(/bytes=(\d*)-(\d*)/); if (result) { start = isNaN(result[1]) ? start : parseInt(result[1]); end = isNaN(result[2]) ? end : parseInt(result[2]) - 1; } } return fs.createReadStream(filepath, { start, end }); }6. Exécution globale de la commandeimplémentée via le lien npm
{ bin: { "hope-server": "bin/hope" } }Créez le fichier Hope du répertoire bin sous le projet et utilisez la ligne de commande de configuration yargs pour transmettre les paramètres
// 告诉电脑用node运行我的文件 #! /usr/bin/env node const yargs = require('yargs'); const init = require('../src/index.js'); const argv = yargs.option('d', { alias: 'root', demand: 'false', type: 'string', default: process.cwd(), description: '静态文件根目录' }).option('o', { alias: 'host', demand: 'false', default: 'localhost', type: 'string', description: '配置监听的主机' }).option('p', { alias: 'port', demand: 'false', type: 'number', default: 8080, description: '配置端口号' }).option('c', { alias: 'child', demand: 'false', type: 'boolean', default: false, description: '是否子进程运行' }) .usage('hope-server [options]') .example( 'hope-server -d / -p 9090 -o localhost', '在本机的9090端口上监听客户端的请求' ).help('h').argv; // 启动服务 init(argv);7 . Exécutez le processus enfant Réalisé via spawnindex.js
const { spawn } = require('child_process'); const Server = require('./hope'); function init(argv) { // 如果配置为子进程开启服务 if (argv.child) { //子进程启动服务 const child = spawn('node', ['hope.js', JSON.stringify(argv)], { cwd: __dirname, detached: true, stdio: 'inherit' }); //后台运行 child.unref(); //退出主线程,让子线程单独运行 process.exit(0); } else { const server = new Server(argv); server.start(); } } module.exports = init; hope.js if (process.argv[2] && process.argv[2].startsWith('{')) { const argv = JSON.parse(process.argv[2]); const server = new Hope(argv); server.start(); }8 Code source et testsAdresse du code source : espérons-. serveur
npm install hope-server -gEntrez n'importe quel répertoire
hope-serverRecommandations associées :
explication détaillée du serveur de fichiers statiques de nœud
Utilisez nodejs, un simple serveur de fichiers statiques HTTP écrit en Python
Version améliorée du fichier statique Node.js server_node.js
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!