這是我第一次使用Node.js來程式設計,而且是建構一個一個靜态檔案資源通路的Http server。
我個人從事java相關的開發差不多有10年了吧,一直都是在建構後端的服務、應用。對于前端一直沒有過多的接觸。對于servlet、jsp等技術也僅限于工作的需要(包含struct等mvc架構)。
最近工作中,參與負責了公司産品Object-Centric理念的開發模式建構。利用Business model對象拉通前後端的開發體驗,通過Business Model 對象組織所有和該業務模型對象關聯的資源:實體模型、試圖模型、服務(rest)、業務校驗、資料轉換處理、頁面等。
目前由于參與到前端頁面相關技術的建構和研究,突然對這方面的技術産生了濃厚的興趣。對Node.js、AngularJS、TypeScript都有興趣深入的學習和使用。後面打算再把mangodb納入到學習計劃中,這樣就把MEAN技術拉通了:)。
下面就是我基于Node.js實作的一個簡單的靜态頁面檔案的http server,總體體驗來說,在編碼的高效性、靈活性等體驗,對比java實作會好很多。但是在類型的識别、編譯錯誤的識别、類型的提示上沒有強語言類型的java來的好。
首先來看一下整個工程的目錄結構:

目錄說明:
HTTP_SERVER:整個工程的根目錄;
app:靜态檔案存放的目錄,對于我來說就是我“未來”期望一個web工程的根目錄,對應于java建構web應用,就是web-app了。
css:用來存放樣式定義檔案
檔案說明:
server.js:提供靜态http服務的主程式。
mine.js:鍵值對的配置檔案,定義了對不同的檔案類型的處理定義。
index.html:web app中的首頁,靜态的html的檔案。
indx.css:index.html首頁引用的層疊樣式表的定義檔案。
首先來看一下server.js的實作:
var http = require('http');
var url = require('url');
var fs = require('fs');
// 自己定義的類型定義檔案
var mine = require('./mine').types;
var path = require('path');
var port = '3000';
var hostname = '127.0.0.1';
var server = http.createServer((req, res) => {
var pathName = url.parse(req.url).pathname;
// url.parse會将一個請求的路徑解析為格式化的輸出
/*
{
protocol : 'http' ,
auth : null ,
host : 'example.com:8080' ,
port : '8080' ,
hostname : 'example.com' ,
hash : null ,
search : '?a=index&t=article&m=default',
query : 'a=index&t=article&m=default',
pathname : '/one',
path : '/one?a=index&t=article&m=default',
href : 'http://example.com:8080/one?a=index&t=article&m=default'
}
*/
var realPath = path.join("app", pathName);
console.log(realPath);
var ext = path.extname(realPath);
ext = ext ? ext.slice(1) : 'unknow';
// ext = ext ? ext.split('.')[1] : 'unknown';
fs.stat(realPath, (err, stats) => {
if (err) {
console.log(err);
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.write(`This request URL ${pathName} was not found on this server.`);
res.end();
} else {
fs.readFile(realPath, "binary", (err, data) => {
if (err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(err);
} else {
console.log(data);
var contentType = mine[ext] || "text/plain";
res.writeHead(200, { 'Content-Type': contentType });
res.write(data, "binary");
res.end();
}
})
console.log(stats);
}
});
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}`);
})
代碼的一點說明:
var ext = path.extname(realPath);
ext = ext ? ext.slice(1) : 'unknow';
這兩句其實是通過截取通路路徑的最後的字元串,來擷取通路的檔案類型。例如,下面的url:http://localhost:3000/index.html。通過這兩句處理之後,ext内的值是html。如果url是:http://localhost:3000/index,那麼ext的值就是unknow。
fs.stat(realPath, (err, stats) => {
}
這個裡面的處理,是我不同于網上參考實作的處理。是我自己查閱了node.js的實作,根據node.js的說明文檔自己添加的,其實就是對檔案的一個預處理,防止對檔案直接操作抛出異常。
再看一下mine.js的代碼實作:
exports.types = {
"html": "text/html",
"xml": "text/xml",
"js": "text/javascript",
"css": "text/css",
"json": "application/json",
"txt": "text/plain",
"pdf": "application/pdf",
"doc": "application/msword",
"xls": "application/vnd.ms-excel",
"ico": "image/x-icon",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"bmp": "image/bmp",
"svg": "image/svg+xml",
"tiff": "image/tiff",
"gif": "image/gif",
"swf": "application/x-shockwave-flash",
"wav": "audio/x-wav",
"wma": "audio/x-ms-wma",
"mp3": "audio/mpeg",
"wmv": "video/x-ms-wmv",
"avi": "video/x-msvideo",
"gz": "application/x-gzip",
"manifest": "text/cache-manifest"
};
這個檔案沒什麼好說的,主要是還i應用在傳回時,設定httpheader的内容使用。
再看一下html,這個也是我參考了網上的實作,不過我稍微做了一點改造,增加了一點javascript的代碼做測試:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>春曉</title>
<link href="./css/index.css" target="_blank" rel="external nofollow" rel="stylesheet" type="text/css">
<script>
function displayDate() {
document.getElementById("demo").innerHTML = Date();
}
</script>
</head>
<body>
<nav>春曉</nav>
<div id="value">
<p>春眠不覺曉</p>
<p>處處聞啼鳥</p>
<p>夜來風雨聲</p>
<p>花落知多少</p>
</div>
<h1>My First JavaScript</h1>
<p id="demo">This is a paragraph.</p>
<button type="button" οnclick="displayDate()">
Display Date</button>
</body>
</html>
再把css的定義檔案貼上來,其實也是我參考網上的實作:
body{
background-color:#222222;
}
nav {
color:#cc0000;
font-weight:bold;
font-size:2em;
}
#value{
color:#cc0000;
font-size:2.1em;
}
運作server.js:
首先通過指令行,進入到工程的根目錄下:
我是在vsc(visula stuido code)中,直接選中server.js右鍵選擇〔在指令提示符中打開〕
在指令中輸入node server.js
回車後,啟動服務,并看到日志輸出:
在浏覽器中輸入:http://localhost:3000/index.html得到的頁面:
就可以正常看到我們定義的app目錄下的index.html檔案,同時在這個檔案中定義的js也可以正常運作。
總結:使用node.js的确可以快速、高效的完成前端的開發,相對于java很高效。同時,對于我習慣于java開發的人來說,裡面的一些文法、寫法确實有些不太習慣。
下一步,是準備利用express這個架構來搭建相同的靜态http server的實作。
在下一步就是建構基于mongodb的小應用了,最後在引入typeScript,嘿嘿,還是挺有意思的。