1 前言
不知從什麼時候開始,本胖就喜歡用一個叫做http-server的中介軟體用來在啟動一個靜態的伺服器以及解決跨域問題。
http-server 是一個簡單的零配置命令列HTTP伺服器, 基於 nodeJs。
現在,本胖要自己從零開始實現一個http-server中介軟體,暫且取名為lpp-http-server,用以致敬偉大的http-server。
2 所用npm包
一般來說寫一箇中介軟體會依賴其他的輔助包,lpp-http-server也不例外。這裡本胖主要依賴瞭如下的npm包。
1.colors--用於在控制檯輸出五顏六色的命令2.commander--提供了使用者命令列輸入和引數解析強大功能3.http-proxy--轉發請求4.pug--模板複製程式碼
3 Server類
這個類是整個lpp-http-server的核心,作用就是實現一個靜態伺服器。主要包含了以下幾個方法。
1.handleRequest——對請求的處理2.sendDir--渲染目錄資訊3.sendFile——獲取檔案資訊4.proxy——轉發介面5.sendError——傳送錯資訊6.start——啟動複製程式碼
下面就來一一介紹這個方法
3.1 handleRequest
async handleRequest(req, res) {
const {
dir, proxyUrl
} = this.config;
let {
pathname
} = url.parse(req.url);
pathname = decodeURIComponent(pathname);
const fileUrl = path.join(dir, pathname);
try {
// 判斷當前路徑是檔案 還是資料夾 const statObj = await stat(fileUrl);
if (statObj.isDirectory()) {
// 資料夾則輸出對應的目錄 this.sendDir(req, res, pathname, fileUrl);
} else {
// 檔案則直接輸出內容 this.sendFile(req, res, statObj, fileUrl);
}
} catch (e) {
// 轉發請求 if (proxyUrl) {
this.proxy(req, res, proxyUrl);
} else {
this.sendError(req, res);
}
}
}複製程式碼
上面是handleRequest方法的全部程式碼,可以看出,主要就是對請求的不同情況的處理,主要處理了以下幾種情況。
1.請求的是檔案地址2.請求的是檔案目錄地址3.請求的地址404複製程式碼
然後對這幾種情況做了分別的處理。
3.2 sendDir
// 獲取資料夾目錄 async sendDir(req, res, pathname, fileUrl) {
// 讀取當前訪問的目錄下的所有內容 readdir 陣列 把陣列渲染回頁面 res.setHeader('Content-Type', 'text/html;
charset=utf8') let dirs = await readdir(fileUrl);
dirs = dirs.map(item =>
({
name: item, // 因為點選第二層時 需要帶上第一層的路徑,所有拼接上就ok了 href: path.join(pathname, item)
})) // 渲染template.html中需要填充的內容,name是當前檔案目錄,arr為當前資料夾下的目錄陣列 const str = pug.render(this.template, {
arr: dirs
});
// 響應中返回填充內容 res.end(str);
}複製程式碼
上面的sendDir方法是用來獲取當前目錄的,主要用了readdir方法來讀取一個目錄的內容,然後迴圈輸出,這裡用了pug當做html模板。pug檔案的主要內容如下
doctype htmlhtml head meta(charset="utf-8") meta(name="renderer", content="webkit") meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1") title lvpp-http-server body block content div - for (var x = 0;
x <
arr.length;
x++) div a(href=arr[x]['href'])= arr[x]['name']複製程式碼
3.3 sendFile
// 獲取檔案資訊 sendFile(req, res, statObj, fileUrl) {
// 管道讀寫操作,將fs.createReadStream(p)的內容寫入到res // return fs.createReadStream(fileUrl).pipe(res);
fs.readFile(fileUrl, 'utf-8', function (err, data) {
if (err) {
throw err;
} res.end(data);
});
}複製程式碼
sendFile方法是用來獲取檔案資訊的,當然最好是用createReadStream方法,他們的區別可以參考node官網。
3.4 proxy
// 代理 proxy(req, res, proxyUrl) {
delete req.headers.host;
var proxy = httpProxy.createProxyServer({
});
proxy.web(req, res, {
target: proxyUrl
});
}複製程式碼
這裡用了http-proxy包進行了轉發,需要注意下面這行程式碼
delete req.headers.host;
複製程式碼
一開始沒有這行程式碼,請求轉發是不行的。
3.5 start
// 啟動 start() {
const server = http.createServer(this.handleRequest.bind(this));
server.listen(this.config.port, this.config.host, () =>
{
console.log(`server start http://${this.config.host
}:${colors.green(this.config.port)
}`);
// 代理 if (this.config.proxyUrl) {
console.log(colors.yellow('Unhandled requests will be served from: ' + this.config.proxyUrl));
}
});
}複製程式碼
啟動的方法主要是啟動一個靜態伺服器http.createServer,然後對該伺服器的一些配置。
4 啟動指令碼
這個指令碼主要是對一些命令的操作,這裡用的是commander這個模組。
#! /usr/bin/env node// 告訴作業系統執行這個指令碼的時候,呼叫 / usr / bin下的node直譯器;const Server = require('../src/index.js');
// 匯入Serverconst commander = require('commander');
// 匯入命令列模組const {
version
} = require('../package.json');
// 讀取package.json的版本// 配置命令列commander .option('-p,--port <
n>
', 'config port') // 配置埠 .option('-o,--host [value]', 'config hostname') // 配置主機名 .option('-d,--dir [value]', 'config directory') // 配置訪問目錄 .option('-P,--proxyUrl [value]', 'config proxy') // 配置轉發地址 .version(version, '-v,--version') // 展示版本 .parse(process.argv);
const server = new Server(commander);
server.start();
複製程式碼
在寫好程式碼之後,我們想要的當然是執行一個自定義命令,就可以執行我們的包了,不用每次都是node ./bin/www.js。
這時候一步配置即可,找到整個專案的package.json檔案,加入以下資訊
"bin": {
"lpp-http-server": "bin/www.js"
},複製程式碼
上面這段命令的意思就是用lpp-http-server這個命令去代替執行node bin/www.js,寫好命令後,還需要在整個目錄下執行
npm link複製程式碼
然後你就會發現你在你電腦任何地方都可以執行lpp-http-server,生成一個靜態伺服器了,效果如下
本文完