nodejs实现简单的Apache功能

实现原理:对于被Apache托管的文件夹,当访问某一个文件的时候,在网页中输入的url是:127.0.0.1:port/index.html,而/index.html对应于文件夹的路径,同理127.0.0.1:port/test/index.html,对应于文件夹的路径:/test/index.html,因此可以获取访问的url,使其对应被管理文件夹的路径。并通过artTemplate模板引擎的使用,对每次访问路径的文件进行获取,并通过同步的方式对文件类型进行判断,并做不同的处理操作。
likeApache

以下的html代码是通过检查Chrome的源代码得到的html源码,对其进行稍微修改即可使用

<html dir="ltr" lang="zh">
<head>
    <meta charset="utf-8">
    <meta name="google" value="notranslate">

    <script>
        function addRow(name, url, isdir,
                        size, size_string, date_modified, date_modified_string) {
            if (name == "." || name == "..")
                return;

            var root = document.location.pathname;
            if (root.substr(-1) !== "/")
                root += "/";

            var tbody = document.getElementById("tbody");
            var row = document.createElement("tr");
            var file_cell = document.createElement("td");
            var link = document.createElement("a");

            link.className = isdir ? "icon dir" : "icon file";

            if (isdir) {
                name = name + "/";
                url = url + "/";
                size = 0;
                size_string = "";
            } else {
                link.draggable = "true";
                link.addEventListener("dragstart", onDragStart, false);
            }
            link.innerText = name;
            link.href = root + url;

            file_cell.dataset.value = name;
            file_cell.appendChild(link);

            row.appendChild(file_cell);
            row.appendChild(createCell(size, size_string));
            row.appendChild(createCell(date_modified, date_modified_string));

            tbody.appendChild(row);
        }

        function onDragStart(e) {
            var el = e.srcElement;
            var name = el.innerText.replace(":", "");
            var download_url_data = "application/octet-stream:" + name + ":" + el.href;
            e.dataTransfer.setData("DownloadURL", download_url_data);
            e.dataTransfer.effectAllowed = "copy";
        }

        function createCell(value, text) {
            var cell = document.createElement("td");
            cell.setAttribute("class", "detailsColumn");
            cell.dataset.value = value;
            cell.innerText = text;
            return cell;
        }

        function start(location) {
            var header = document.getElementById("header");
            header.innerText = header.innerText.replace("LOCATION", location);
            // 将标题改成h1标签中的内容
            // document.getElementById("title").innerText = header.innerText;
        }

        function onHasParentDirectory() {
            var box = document.getElementById("parentDirLinkBox");
            box.style.display = "block";

            var root = document.location.pathname;
            if (!root.endsWith("/"))
                root += "/";

            var link = document.getElementById("parentDirLink");
            link.href = root + "..";
        }

        function onListingParsingError() {
            var box = document.getElementById("listingParsingErrorBox");
            box.innerHTML = box.innerHTML.replace("LOCATION", encodeURI(document.location)
                + "?raw");
            box.style.display = "block";
        }

        function sortTable(column) {
            var theader = document.getElementById("theader");
            var oldOrder = theader.cells[column].dataset.order || '1';
            oldOrder = parseInt(oldOrder, 10)
            var newOrder = 0 - oldOrder;
            theader.cells[column].dataset.order = newOrder;

            var tbody = document.getElementById("tbody");
            var rows = tbody.rows;
            var list = [], i;
            for (i = 0; i < rows.length; i++) {
                list.push(rows[i]);
            }

            list.sort(function (row1, row2) {
                var a = row1.cells[column].dataset.value;
                var b = row2.cells[column].dataset.value;
                if (column) {
                    a = parseInt(a, 10);
                    b = parseInt(b, 10);
                    return a > b ? newOrder : a < b ? oldOrder : 0;
                }

                // Column 0 is text.
                if (a > b)
                    return newOrder;
                if (a < b)
                    return oldOrder;
                return 0;
            });

            // Appending an existing child again just moves it.
            for (i = 0; i < list.length; i++) {
                tbody.appendChild(list[i]);
            }
        }

        // Add event handlers to column headers.
        function addHandlers(element, column) {
            element.onclick = (e) => sortTable(column);
            element.onkeydown = (e) => {
                if (e.key == 'Enter' || e.key == ' ') {
                    sortTable(column);
                    e.preventDefault();
                }
            };
        }

        function onLoad() {
            addHandlers(document.getElementById('nameColumnHeader'), 0);
            addHandlers(document.getElementById('sizeColumnHeader'), 1);
            addHandlers(document.getElementById('dateColumnHeader'), 2);
        }

        window.addEventListener('DOMContentLoaded', onLoad);
    </script>

    <style>

        h1 {
            border-bottom: 1px solid #c0c0c0;
            margin-bottom: 10px;
            padding-bottom: 10px;
            white-space: nowrap;
        }

        table {
            border-collapse: collapse;
        }

        th {
            cursor: pointer;
        }

        td.detailsColumn {
            -webkit-padding-start: 2em;
            text-align: end;
            white-space: nowrap;
        }

        a.icon {
            -webkit-padding-start: 1.5em;
            text-decoration: none;
            user-select: auto;
        }

        a.icon:hover {
            text-decoration: underline;
        }

        a.file {
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;
        }

        a.dir {
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;
        }

        a.up {
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;
        }

        html[dir=rtl] a {
            background-position-x: right;
        }

        #parentDirLinkBox {
            margin-bottom: 10px;
            padding-bottom: 10px;
        }

        #listingParsingErrorBox {
            border: 1px solid black;
            background: #fae691;
            padding: 10px;
            display: none;
        }
    </style>

    <title id="title">{{ title }}</title>

</head>

<body>

<div id="listingParsingErrorBox">糟糕!Google Chrome无法解读服务器所发送的数据。请<a
        href="http://code.google.com/p/chromium/issues/entry">报告错误</a>,并附上<a href="LOCATION">原始列表</a></div>

<h1 id="header">{{ titleName}}的索引</h1>

<div id="parentDirLinkBox" style="display: block;">
    <a id="parentDirLink" class="icon up" href="/E:/%E5%89%8D%E7%AB%AF/nodejs/%E5%AE%9E%E8%B7%B5/css/..">
        <span id="parentDirText">[上级目录]</span>
    </a>
</div>

<table>
    <thead>
    <tr class="header" id="theader">
        <th id="nameColumnHeader" tabindex="0" role="button">名称</th>
        <th id="sizeColumnHeader" class="detailsColumn" tabindex="0" role="button">
            大小
        </th>
        <th id="dateColumnHeader" class="detailsColumn" tabindex="0" role="button">
            修改日期
        </th>
    </tr>
    </thead>
    <tbody id="tbody">
    {{ each files }}
    <tr>
        <td data-value="{{ $value.fileName }}"><a class="icon {{ $value.isFile }}" draggable="true"
                                            href="http://127.0.0.1:3000{{ $value.url }}/{{ $value.fileName }}">{{ $value.fileName }}</a>
        </td>
        <td class="detailsColumn" data-value="168">168 B</td>
        <td class="detailsColumn" data-value="1614861514">2021/3/4 下午8:38:34</td>
    </tr>
    {{ /each }}
    </tbody>
</table>

<script>start("E:\\前端\\nodejs\\实践");</script>
<script>onHasParentDirectory();</script>
<script>addRow("practice_01.css", "practice_01.css", 0, 168, "168 B", 1614861514, "2021/3/4 下午8:38:34");</script>
</body>
</html>
let fs = require('fs');
let http = require('http');
let artTemplate = require('art-template');

let server = http.createServer();
var dir = 'E:/前端/nodejs/实践';
server.on('request',(req,res) => {
    let url = req.url
    // 创建正则表达式
    // 找出xx.xx格式的文件
    let regExp = new RegExp(/[\w]+?\.[\w]+?/);
    // 找出.xx文件
    let regExp_02 = new RegExp(/\.[\w]+?/);
    // 如果是文件类型的数据,则显示文件内容
    // console.log(url);
    // console.log(regExp.test(url));
    if (regExp.test(url) && url != '/favicon.ico') {
    //    读取文件显示网页内容
        fs.readFile(dir + url,(err,data) => {
            if (err) {
                return res.end('Read File Faild!');
            }
            res.end(data);
        })
    } else if(regExp_02.test(url)) {
        // 如果是.xx文件类型,则不可被访问
        // 因为有中文 因此需要编码
        res.setHeader('Content-Type','text/html; charset=utf-8');
        res.end('<h1 style="color: red">该文件不能被访问!</h1>\n');
    } else {
        // 如果不是文件则展示树状目录结构
        fs.readFile('../html/likeApache.html',(err,data) => {
            if (err) {
                return res.end('404 Not Found');
            }
            // 读取目录内容
            fs.readdir(dir + url,(err,files) => {
                if (err) {
                    return res.end('404 Not FIles');
                }
                // 采用模板引擎渲染目录内容
                // 判断文件类型 过滤文件夹
                // console.log(fs.lstatSync(dir + url).isFile());
                let newFiles = [];
                files.forEach((item,index) => {
                    let newObj = {};
                    // 该文件类型为文件
                    if (fs.lstatSync(dir+url+'/'+item).isFile()) {
                        newObj.isFile = 'file';
                    } else {
                        // 该文件为文件夹
                        newObj.isFile = 'dir';
                    }
                    newObj.fileName = item;
                    // 如果路径仅仅是/会导致出现两个/的情况 导致返回主目录不成功的情况出现
                    newObj.url = url == '/'? '':url;
                    // 存储当前文件名词
                    newFiles[index] = newObj;
                })
                // console.log(newFiles);
                // console.log(newFiles);
                // 采取模板引擎的方式进行数据的替换
                let str = artTemplate.render(data.toString(),{
                    titleName: `E:\\前端\\nodejs\\实践 目录下`,
                    title: 'LikeApache',
                    files: newFiles
                })
                // console.log(files);
                res.end(str);
            })
        })
    }
})

server.listen(3000,(err) => {
    console.log('server is running...');
})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值