使用node.js仿写Apache
Git仓库:https://github.com/mandongpiaoxue/apache
本文原创,引用请注明出处
文件说明:
config.json //配置文件 images.js //引入的svg图片 server.js //服务器文件 run.bat //window中启动文件,双击立即启动服务
1. config.json文件的配置
{ "index": "index", //首页名字 "deny": { //拒绝IP的访问 "ips": [ "192.168.0.10" ] }, "hosts": [ { "host": "127.0.0.1", //配置域名 "dir": "D:/www" //配置路径 }, { "host": "www.man.cn", "dir": "D:/www" } ] }
2. run.bat文件代码
@cd /d %~dp0
@echo Node.js服務器啟動成功
@node server.js
3. server.js文件代码与说明
3.1 引入模块和文件
//引入模块
const http = require('http') const url = require('url') const fs = require('fs') const path = require('path') const images = require('./images') //引入图片
//定义变量 var config = [] var ips = [] var index = ''
//读取配置文件 fs.readFile(path.join(__dirname, 'config.json'), (err, data) => { config = JSON.parse(data.toString()) ips = config.deny.ips index = config.index })
3.2 写readfile函数:方便我们使用promise,简洁写代码
function readFile(file) { return new Promise((resolve, reject) => { fs.readFile(file, (error, data) => { if (error) { reject(error) } else { resolve(data) } }) }) }
3.3 server代码及注释
http .createServer(function (req, res) { /* 獲取遠程IP */ let remoteIp = req.socket.remoteAddress.substr(7) /* 屏蔽指定IP */ ips.forEach(ip => { if (ip === remoteIp) res.end('404 file no found!') }) /* 获取host,即域名 */ let host = req.headers.host /* 如果通過非80端口接入,會存在protocol,否則為null */ let protocol = url.parse(host).protocol if (protocol) host = protocol.slice(0, -1) /* 格式化Url */ let urlObject = url.parse(req.url, true) /* 获取路径名 */ let pathname = urlObject.pathname pathname = decodeURIComponent(pathname) /* 获取后缀名 */ let ext = path.parse(pathname).ext /* 查找访问的域名对应的相关配置 */ let server = config.hosts.find((v, i) => { return v.host === host }) /* 讀取匹配的路徑 */ if (!server.dir) res.end('域名未指向路径!') fs.readdir(server.dir, (error, data) => { if (error) res.end('域名指向路径错误') }) switch (ext) { /* 對.htm和.htm文件進行頭設置,防止部分html或htm文件無法解讀 */ case '.html': res.setHeader('Content-Type', 'text/html;chartset=utf-8') break case '.htm': res.setHeader('Content-Type', 'text/html;chartset=utf-8') break case '.txt': res.setHeader('Content-Type', 'text/plain;chartset=utf-8') break case '.css': res.setHeader('Content-Type', 'text/css;chartset=utf-8') break case '.doc': res.setHeader('Content-Type', 'application/msword;chartset=utf-8') break } let dir = server.dir let filePath = dir + pathname /* 以文件夾/目录形式讀取Url */ fs.readdir(filePath, (ed, dd) => { if (ed) { /* 直接讀取文件 */ readFile(filePath + '') .then(d1 => { res.end(d1) }, e1 => { res.setHeader('Content-Type', 'text/html;chartset=utf-8') /* 以省略.htm的形式讀取文件 */ return readFile(filePath + '.htm') }) .then(d2 => { res.end(d2) }, e2 => { /* 以省略.html的形式讀取文件 */ return readFile(filePath + '.html') }) .then(d3 => { res.end(d3) }, e3 => { res.end('404 file no found!') }) } else { /* 以html类型读取文件,所以设置响应头为'text/html;chartset=utf-8' */ res.setHeader('Content-Type', 'text/html;chartset=utf-8') /* 讀取目錄下的index.html文件 */ readFile(filePath + '/' + index + '.html') .then(d1 => { res.end(d1) }, e1 => { /* 讀取目錄下的index.htm文件 */ return readFile(filePath + '/' + index + '.htm') }) .then(d2 => { res.end(d2) }, e2 => { /* 讀取目錄下的index文件 */ return readFile(filePath + '/' + index) }) .then(d3 => { res.end(d3) }, e3 => { /* 如果没有index文件,则讀取目錄下的文件 */ let pna = pathname.split('/') pna.pop() let name = pna.pop() let pn = pathname.slice(0, -1) let pnl = pn.lastIndexOf('/') let upPath = pathname.slice(0, pnl + 1) let ds = ` <meta charset="UTF-8"> <title>${name}</title> <style> body{padding:20px 50px;} </style> <a style="display:block;height:32px;" href="${upPath}">${images.back}</a> ` dd.forEach(file => { if (file.search('\\\.') > -1) { ds += `<a style="display:block;height:32px;" href="${pathname + file}"><span style="height:32px;line-height:32px;float:left;display:block;">${images.file}</span><span style="height:32px;line-height:32px;float:left;display:block;">${file}</span></a>` } else { ds += `<a style="display:block;height:32px;" href="${pathname + file + '/'}"><span style="height:32px;line-height:32px;float:left;display:block;">${images.folder}</span><span style="height:32px;line-height:32px;float:left;display:block;">${file}</span></a>` } }) res.end(ds) }) } }) }) .listen(80, function (err) { if (err) console.log(err) })
4. 效果图