快速启动一个本地web server

weifeng 2020/06/28

目录

在本地、开发机上工作时,有时想下载或预览一些文件,需要临时开一个Web Server,参考当时服务器已安装的软件,可尝试下列几种方式:

python2

python -m SimpleHTTPServer 8080

python3

python -m http.server 8080

php

php -S 0.0.0.0:8080

# 完整参数
# php [options] -S <addr>:<port> [-t docroot] [router]

nginx

如果已经安装了nginx,但又不想影响正常服务,可以临时起一个新的server。

编辑一个新的conf文件,如my_server.conf, 内容:

daemon off; # 前台运行,防止忘记停服务的安全风险。如不需要可删除这行。
events {
    worker_connections 32;
}
http {
    server {
        listen 8080;
        location / {
            root   /root/www; # 根目录
            autoindex on;     # 打开索引
        }
    }
}

编辑完成,运行:

nginx -c /path/to/my_server.conf # 注意完整路径

node npm

npm install -g http-server
http-server -p 8080

nodejs

上面介绍了npm安装包的方式,如果仍觉麻烦,可以直接编辑文件server.js并运行:

function startServer() {
    const args = process.argv.slice(2);
    const cluster = require('cluster');
    const numCPUs = require('os').cpus().length;

    if(args[0] === '-h' || args[0] === '--help') {
        console.log("node server.js [port] [host]");
        return;
    }

    if (cluster.isMaster) {
        console.log('[pid:%s] Master is running', process.pid);
        for (let i = 0; i < numCPUs; i++) cluster.fork();
        return;
    }

    const util = require('util');
    const fs = require('fs');
    const http = require('http');
    const port = parseInt(args[0]) || 8080;
    const url = require('url');
    const stat = util.promisify(fs.stat);
    const readdir = util.promisify(fs.readdir);
    const access = util.promisify(fs.access);
    const path = require('path');
    const mimeType = {};
    const texts = 'txt|html|htm|js|json|css|ini|py|sh|log|org|php|md'.split('|').forEach(v => mimeType[`.${v}`] = `text/${v}`);
    const images = 'jpg|png|jpeg|gif'.split('|').forEach(v => mimeType[`.${v}`] = `image/${v}`);
    var host = args[1] || 'localhost';
    var server = http.createServer(async function (request, res) {
        var u = url.parse(request.url); 
        var prefix = u.pathname;
        var filepath = '.' + decodeURIComponent(u.pathname);
        var s = await stat(filepath).catch(e=>{page(404, 'Not Found');});
        if(!s) return;
        if(s.isFile()) {
            access(filepath, fs.constants.F_OK | fs.constants.R_OK)
                .catch(e=>{ page(403, 'File Read Error'); })
                .then(function() {
                    var ext = path.parse(filepath).ext;
                    res.setHeader('Content-type', mimeType[ext.toLowerCase()] || 'application/octet-stream');
                    fs.createReadStream(filepath, {"bufferSize": 4096})                    
                        .on('end', function() {
                            console.log(['HTTP', 200, filepath.slice(1)].join(' '));
                        })
                        .pipe(res);
                });
        }
        else if(s.isDirectory()) {
            var files = await readdir(filepath).catch(e=>{ page(403, 'Dir Read Error'); });
            if(prefix !== "/") prefix += '/';
            var html = files.map(f => `<a href="${prefix}${f}">${f}</a>`).join('<br>');
            page(200, html, '.html');
        }
        else page(403, 'Forbidden');

        function page(statusCode, html, mime) {
            res.statusCode = statusCode;
            res.setHeader('Content-type', 'text/html;charset=utf-8');
            res.write(html || '');
            res.end();
            console.log(['HTTP', statusCode, filepath.slice(1)].join(' '));
        }
    }).listen(port, host);
    server.on('error', function(e) {
        if (e.code === 'EADDRINUSE') {
            console.error(`port[${port}] in use, retrying...`);
            setTimeout(() => {
                server.close();
                server.listen(port, host);
            }, 1000);
        }
        else console.error(e);
    })
    console.log('[pid:%s] server start at %s:%s', process.pid, host, port);
}

startServer(); // 启动服务

编辑完成,运行:

node server.js # 默认8080端口

# 该示例使用了cluster,可以充分利用机器的多核性能
# 完整用法:
# node server.js [port] [host]