思科DevNet

Node学习之手写一个http-server

2020-11-16  本文已影响0人  Mstian

模仿http-server创建一个静态服务器。
http-server地址 https://www.npmjs.com/package/http-server

功能:Http-server是一个轻量级的基于nodejs的http服务器,可以使任意一个目录成为服务器的目录。

安装:npm i -g http-server

使用:http-server(在想要使用的目录下直接使用命令)常用在测试Vue React等单页应用打包之后想要预览效果,缺不方便部署到服务器时。

阅读该文章可以获取到的知识:

  1. node命令行交互使用的一些常用包(commander)
  2. npm link命令,将npm 模块链接到对应的运行项目中去,方便地对模块进行调试和测试。

首先使用npm init -y创建一个新的项目


项目目录图

项目目录图如上所示。
分别来介绍下每个目录的作用,在使用命令行命令时package.json中的bin属性指明了需要运行的文件:

{
  "name": "node-http-server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "bin": {
    "node-http-server": "./bin/www.js"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "chalk": "^4.1.0",
    "commander": "^6.2.0",
    "ejs": "^3.1.5",
    "mime": "^2.4.6",
    "mz": "^2.7.0",
    "url": "^0.11.0"
  }
}

然后在bin/www.js文件中编写交互代码

#!/usr/bin/env node

const { program } = require('commander');
const json = require('../package.json');

const Server = require('../Server');
program.version(json.version)
.option('-p --port <port>', '端口号')
.option('-d --dir <dir>', '目录')
.option('-h --host <host>', '主机')
.parse(process.argv);

program.on('--help', () => {
    console.log('');
    console.log('Example call:');
    console.log('  $ custom-help --help');
});

let config = {
    port: program.port,
    host: program.host,
    dir: program.dir
}

let server = new Server(config);
server.start();

在文件的顶部必须加上 #!/usr/bin/env node 作用是告诉操作系统执行这个脚本的时候,调用/usr/bin下的node解释器。具体的我也不是很了解操作系统这块,可以参考网上资料。https://www.cnblogs.com/qinmengjiao123-123/p/8503163.html

然后使用commander模块,这是一个第三方模块参考:https://www.kancloud.cn/diaoyundexia/text/149934,commander模块用来制作命令行交互;一般命令行包含:命令,选项,参数。
具体可以看npm官网或者其他资料,在这里就只粗略用了下。
process.argv 属性会返回一个数组,其中包含当 Node.js 进程被启动时传入的命令行参数,通过program.parse方法会被直接解析,所以参数部分会根据前面的option中配置的命令直接解析。

最后实例一个Server类,传递端口号,启动的目录,还有主机名,调用类上的start方法来启动服务。

先看一下交互:
在命令行输入命令 node-http-server --help

交互效果

const http = require('http');
const fs = require('mz/fs');
const mime = require('mime');
const chalk = require('chalk');
const path = require('path');
const url = require('url');
const ejs = require('ejs');
let template = fs.readFileSync(path.join(__dirname, 'template.html'), 'utf-8');
const baseConfig = {
    port: 3000,
    host: '127.0.0.1',
    dir: process.cwd()
}
class Server{
    constructor({port, host, dir}){
        this.port = port || baseConfig.port;
        this.host = host || baseConfig.host;
        this.dir = dir || baseConfig.dir;
        this.template = template;
    }
    start() {
        let server = http.createServer(this.sendRequest.bind(this));
        server.listen(this.port, this.host, () => {
            console.log(chalk.yellow(`服务启动, 服务路径是${this.dir}`));
            console.log(chalk.green(`http://${this.host}:${this.port}`));
        })
    }
    async sendRequest(req, res) {
        try{
            let {pathname} = url.parse(req.url);
            let currentPath = path.join(this.dir, pathname);
            let stats = await fs.stat(currentPath);
            if(stats.isDirectory()) {
                let dirs = await fs.readdir(currentPath);
                let datas = dirs.map((item, index) => {
                    return {
                        href: path.join(pathname, item),
                        content: item
                    }
                })
                let str = ejs.render(this.template, {data: datas});
                res.setHeader('Content-type', 'text/html; charset-utf8');
                res.end(str);
            } else {
                this.responseData(req, res, currentPath);
            }
        }catch(e){
            console.log(e);
            this.sendError(req, res);
        }
    }
    responseData(req, res, currentPath) {
        res.setHeader('Content-type', mime.getType(currentPath) +'; charset=utf8');
        fs.createReadStream(currentPath).pipe(res);
    }
    sendError(req, res) {
        res.statusCode = 404;
        res.end('Not Found');       
    }
}

module.exports = Server;

Server主要的逻辑就是考虑服务启动后服务的目录是一个文件还是文件夹,是文件直接读取展示,是文件夹用ejs模板直接渲染输出到页面,并且添加a链接可以点击进入。

最终在命令行输入命令 node-http-server -p 3000 还可以传其他参数,这里只传了port。

效果:


预览效果1 预览效果2.png

项目源代码地址:https://github.com/Mstian/node-static-server

上一篇下一篇

猜你喜欢

热点阅读