Maison > Article > interface Web > Exemple de code pour le serveur de fichiers statiques de nœud réel
Cet article présente principalement des exemples de serveurs de fichiers statiques de nœuds réels. Maintenant, je les partage avec vous et leur donne une référence.
Cet article présente principalement des exemples de serveurs de fichiers statiques de nœuds réels et les partage avec tout le monde. Les détails sont les suivants :
Fonctions prises en charge :
. Lire les fichiers statiques
peut trouver automatiquement le fichier index.html suivant lors de l'accès au répertoire. S'il n'y a pas d'index.html, la liste des fichiers sera répertoriée
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 pour gérer spécifiquement les requêtes et renvoyer du statique. fichiers. 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); // 读取文件,并响应 }Prise en charge de 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, répertoriez le répertoire de fichiers :
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); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>{{title}}</title> </head> <body> <h1>hope-server静态文件服务器</h1> <ul> {{#each files}} <li> <a href={{url}}>{{name}}</a> </li> {{/each}} </ul> </body> </html>2. Prise en charge du type MIMEUtilisez le module MIME pour obtenir le type de fichier et définir l'encodage :
res.setHeader('Content-Type', mime.getType(filepath) + ';charset=utf-8');3. Prise en charge du cacheCache du protocole http :Cache-Control : contenu http1.1, indique au client comment mettre en cache les données et les règles
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 dans l'en-tête de la requête .CompressionLe client envoie du contenu et l'informe. serveur quels formats de compression sont pris en charge via Accept-Encoding : gzip, deflate dans l'en-tête de la requête. 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 requêtes 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-serverCe qui précède est ce que j'ai compilé pour vous, j'espère que cela vous sera utile à l'avenir. Articles connexes :
Comment implémenter la concaténation de chaînes dans JS (extension de String.prototype.format)
Utiliser ES6 Résoudre la mémoire problème de fuite via WeakMap (tutoriel détaillé)
Comment implémenter le code de commutation aléatoire de l'identifiant WeChat via JavaScript (tutoriel détaillé)
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!