日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用node搭一个静态服务

發布時間:2025/3/21 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用node搭一个静态服务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如何搭一個靜態服務

  • 新建一個文件夾
  • 初始化 npm init -y
  • 所用到的模塊
    • http-server 起服務
    • mime chalk debug ejs 所需模塊
    • http fs util path自帶模塊
    • yargs

    目錄結構

    啟動一個服務需要 src/congfig文件

    • 運行的條件 指定主機名
    • 指定啟動的端口號
    • 自定運行的目錄

    通過config配置 app起服務 tepl編譯 bin和package.json鏈接命令行

    配置

    config.js

    //將配置掛載在我們的實例上,方便后期手動指定,直接get就可以 let path = require('path') let config = {hostname : '127.0.0.1', //主機port:3000, //端口號dir:path.join(__dirname, 'public') } module.exports = config; 復制代碼

    tmpl

    <!--ejs模版,當是文件夾的時候會用到--> <body><%dirs.map(item=>{%><li><a href="<%=item.pathname%>"><%=item.filename%></a></li> <%})%> </body> 復制代碼

    配置全局管理 (全局映射關系)

    package.json

    //添加bin配置 "bin": { "zdl": "bin/www.js" }, 復制代碼

    執行npm link

    bin/www.js 用此文件作為入口,幫我們引用app.js

    #! /usr/bin/env node //yargs用法 在命令行輸入`zdl --help`測試是否生效 // 第一執行了命令后 會執行 bin/www.js let yargs = require('yargs') let argv = yargs.option('port', {alias: 'p',default: 3000, //默認demand: false, //是否必填description: 'this is port' }).option('hostname', {alias: 'host',default: 'localhost',type: String, //類型demand: false,description: 'this is hostname' }).option('dir', {alias: 'd',default: process.cwd(),type: String,demand: false,description: 'this is cwd' }).usage('zdl [options]').argv; //用法提示 //用此文件作為入口,幫我們引用app.js let Server = require('../src/app'); new Server(argv).start(); // 開啟服務 //相當于在app.js執行 //let server = new Server(argv); //server.start(); 復制代碼

    app.js

    架子

    // 實現一個靜態服務 let http = require('http'); let fs = require('fs'); let url = require('url'); let util = require('util'); let path = require('path');let mime = require('mime'); let ejs = require('ejs'); // 渲染模板 let chalk = require('chalk'); // 粉筆 let debug = require('debug')('*');//所有的都輸出 // 第二個參數可以指定環境變量在為什么值時才打印 // window set DEBUG=XXX export DEBUG=XXXXclass Server {constructor(args) { //config在調用此文件時傳參argsconstructor(args) {this.config = {...config,...args},this.template = template;//渲染模版}async handleRequest(req, res) { // 這里的this都是實例let { pathname } = url.parse(req.url, true);let p = path.join(this.config.dir, pathname);try{let statObj = await stat(p);if (statObj.isDirectory()) {//若是文件夾直接渲染數據let dirs = await readdir(p);dirs = dirs.map(dir => { return {filename: dir, pathname: path.join(pathname, dir)}}); let str = ejs.render(this.template, { dirs, title: 'ejs' });//template渲染模板,數據,渲染結果是字符串res.setHeader('Content-Type', 'text/html;charset=utf8');res.end(str);} else {// 文件 發送文件this.sendFile(req, res, p, statObj);}} catch (e) {// 文件不存在的情況this.sendError(req, res, e);}}//創建服務start() {let server = http.createServer(this.handleRequest.bind(this));//this.handleRequest,this是回調函數的this,也可以在該函數return 箭頭函數let { hostname, port } = this.config;debug(`http://${hostname}:${chalk.green(port)} start`)server.listen(port, hostname);}//錯誤處理sendError(){// 解析字符串打印對象//debug(util.inspect(e).toString());res.statusCode = 404;res.end(`Not Found`);}//發送文件sendFile(){...} }module.exports = Server; 復制代碼

    添加功能

    添加的三個功能都是http的應用,想更具體請參考node~http緩存

    class Server {// 添加緩存功能呢cache(req, res, p, stat) {}//添加壓縮功能gzip(req, res, p, stat) {}//添加范圍請求功能range(req, res, p, stat) {}//如果是文件sendFile(req, res, p, stat) {} } 復制代碼

    如果是目錄 就將目錄中的內容展現出來. 如果是文件就將文件展示出來

    cache

    // 添加緩存功能呢cache(req, res, p, stat) { //Catch-Control Expries if-modified-since if-none-matchlet since = req.headers['if-modified-since'];let match = req.headers['if-none-match'];let ssince = stat.ctime.toUTCString();let smatch = stat.ctime.getTime() + stat.size;res.setHeader('Last-Modified', ssince);res.setHeader('ETag', smatch);res.setHeader('Cache-Control', 'max-age=6');if (since != ssince) {debug(since, ssince);return false;}if (match != smatch) {debug(match, smatch);return false}return true;}//如果是文件sendFile(req, res, p, stat) {if (this.cache(req, res, p, stat)) {// 檢測是否有緩存res.statusCode = 304;res.end();return;}res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p, { start, end }).pipe(res);} 復制代碼

    gzip

    //添加壓縮功能gzip(req, res, p, stat) {let header = req.headers['accept-encoding'];if (header) {if (header.match(/\bgzip\b/)) {res.setHeader('Content-Encoding', 'gzip')return zlib.createGzip();} else if (header.match(/\bdeflate\b/)) {res.setHeader('Content-Encoding', 'deflate')return zlib.createDeflate();}} else {return false;}}//如果是文件sendFile(req, res, p, stat) {...let compress = this.gzip(req, res, p, stat);if (compress) { // 返回的是一個壓縮流res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p).pipe(compress).pipe(res);} else {res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p).pipe(res);}} 復制代碼

    range

    //添加范圍請求功能range(req, res, p, stat) {let range = req.headers['range'];if(range){let [, start, end] = range.match(/(\d*)-(\d*)/) || [];start = start ? parseInt(start) : 0;end = end ? parseInt(end) : stat.size;res.statusCode = 206;res.setHeader('Accept-Ranges', 'bytes');res.setHeader('Content-Length', end - start + 1);res.setHeader('Content-Range', `bytes ${start}-${end}/${stat.size}`);return { start, end };}else{return {start:0,end:stat.size}}}//如果是文件sendFile(req, res, p, stat) {let { start, end } = this.range(req, res, p, stat);if (compress) { // 返回的是一個壓縮流res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p, { start, end }).pipe(compress).pipe(res);} else {res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p, { start, end }).pipe(res);}} 復制代碼

    小結

    以下是整個app.js的內容

    // 實現一個靜態服務 // 如果是目錄 就將目錄中的內容展現出來 // 如果是文件就將文件展示出來 let http = require('http'); let fs = require('fs'); let url = require('url'); let zlib = require('zlib'); let util = require('util'); let path = require('path');let mime = require('mime'); let ejs = require('ejs'); // 渲染模板 let chalk = require('chalk'); // 粉筆 // 第二個參數可以指定環境變量在為什么值時才打印 // window set DEBUG=XXX export DEBUG=XXXX let debug = require('debug')('*'); // 運行的條件 指定主機名 // 指定啟動的端口號 // 自定運行的目錄 let stat = util.promisify(fs.stat); let readdir = util.promisify(fs.readdir); let config = require('./config'); let template = fs.readFileSync(path.resolve(__dirname, 'tmpl.html'), 'utf8'); class Server {constructor(args) {this.config = { ...config, ...args };// 將配置掛載在我們的實例上this.template = template;}async handleRequest(req, res) { // 這里的this都是實例let { pathname } = url.parse(req.url, true);let p = path.join(this.config.dir, pathname);// 1.根據路徑 如果是文件夾 顯示文件夾里的內容// 2.如果是文件 顯示文件的內容try { // 如果沒錯誤說明文件存在let statObj = await stat(p);if (statObj.isDirectory()) {// 現在需要一個當前目錄下的解析出的對象或者數組let dirs = await readdir(p);dirs = dirs.map(dir => { // dirs就是要渲染的數據return {filename: dir,pathname: path.join(pathname, dir)}});let str = ejs.render(this.template, { dirs, title: 'ejs' });res.setHeader('Content-Type', 'text/html;charset=utf8');res.end(str);} else {// 文件 發送文件this.sendFile(req, res, p, statObj);}} catch (e) {// 文件不存在的情況this.sendError(req, res, e);}}// 實現其他功能// 實現范圍請求// 實現緩存// 服務器 Cache-Control Expires // Last-Modified ETag:ctime+size// 客戶端// if-modified-since if-none-matchcache(req, res, p, stat) {// 實現緩存 let since = req.headers['if-modified-since'];let match = req.headers['if-none-match'];let ssince = stat.ctime.toUTCString();let smatch = stat.ctime.getTime() + stat.size;res.setHeader('Last-Modified', ssince);res.setHeader('ETag', smatch);res.setHeader('Cache-Control', 'max-age=6');if (since != ssince) {debug(since, ssince);return false;}if (match != smatch) {debug(match, smatch);return false}return true;}// 實現服務端壓縮gzip(req, res, p, stat) {let header = req.headers['accept-encoding'];if (header) {if (header.match(/\bgzip\b/)) {res.setHeader('Content-Encoding', 'gzip')return zlib.createGzip();} else if (header.match(/\bdeflate\b/)) {res.setHeader('Content-Encoding', 'deflate')return zlib.createDeflate();}} else {return false;}}range(req, res, p, stat) {let range = req.headers['range'];if(range){let [, start, end] = range.match(/(\d*)-(\d*)/) || [];start = start ? parseInt(start) : 0;end = end ? parseInt(end) : stat.size;res.statusCode = 206;res.setHeader('Accept-Ranges', 'bytes');res.setHeader('Content-Length', end - start + 1);res.setHeader('Content-Range', `bytes ${start}-${end}/${stat.size}`);return { start, end };}else{return {start:0,end:stat.size}}}sendFile(req, res, p, stat) {if (this.cache(req, res, p, stat)) {// 檢測是否有緩存res.statusCode = 304;res.end();return};let compress = this.gzip(req, res, p, stat);let { start, end } = this.range(req, res, p, stat); //范圍請求,返回開始位置和結束位置if (compress) { // 返回的是一個壓縮流res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p, { start, end }).pipe(compress).pipe(res);} else {res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');fs.createReadStream(p, { start, end }).pipe(res);}}sendError(req, res, e) {// 解析字符串打印對象//debug(util.inspect(e).toString());res.statusCode = 404;res.end(`Not Found`);}start() {let server = http.createServer(this.handleRequest.bind(this));let { hostname, port } = this.config;debug(`http://${hostname}:${chalk.green(port)} start`)server.listen(port, hostname);} } // 開啟一個服務 module.exports = Server 復制代碼

    現在你只需要在cmd里面輸入zdl就可以啟動一個靜態服務了

    發布到npm

    發包

    在用的時候我們可以直接 npm install [name] 然后zdl運行

    總結

    以上是生活随笔為你收集整理的用node搭一个静态服务的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。