首頁 >web前端 >js教程 >Node.js實戰 建立簡單的Web伺服器

Node.js實戰 建立簡單的Web伺服器

高洛峰
高洛峰原創
2016-12-28 11:24:02996瀏覽

如果你熟悉.NET或其他類似平台的Web開發,你可能會像,建立一個Web伺服器有什麼,在Visual Studio中建立一個Web工程,點擊運行即可。事實的確是這樣,但請不要忘記,這樣的代價是,比如果說,你是用.NET開發Web應用,你就使用了完整的IIS作為你的Web伺服器基礎,這樣當你的應用程式發佈時就只能用IIS了。而如果使用獨立伺服器(利用System.Web.Hosting自己建立的話),你則必須處理各種HttpListener和對應線程,則會比較麻煩,畢竟.NET不是專注於面向Web的。 Node.js在這方面提供了方便且可自訂的途徑,你可以在其基礎上建立精巧且完全面向你應用的服務平台。


一、建立簡單的Web伺服器涉及到Node.js的一些基本知識點: 

1、請求模組 
在Node.js中,系統提供了許多有用的模組(當然也可以用JavaScript寫自己的模組,以後的章節我們將詳細講解),如http、url等。模組封裝特定的功能,提供對應的方法或屬性,要使用這些模組,需要先請求模組取得其操作物件。 

例如要使用系統的http模組,可以這樣寫: 

var libHttp = require('http'); //请求HTTP协议模块

這樣,以後的程式將可以透過變數libHttp存取http模組的功能。本章例程中使用了以下系統模組: 
http:封裝http協定的伺服器與用戶端實作; 
url:封裝對url的解析與處理; 
fs:封裝對檔案系統操作的功能; 
path:封裝對路徑的解析功能。 
有了這些模組,我們就可以站在巨人的肩膀上建造自己的應用。 
2、控制台 
為了更好的觀察程式的運行,方便在異常時查看錯誤,可以通便變數console使用控制台的功能。

console.log('这是一段日志信息'); 
计时并在控制台上输出计时信息: 
//开始计时 
console.timeEnd('计时器1'); //开始名称为“计时器1”的计时器 
... 
... 
... 
//结束计时,并输出到控制台 
console.timeEnd('计时器1'); //结束称为“计时器1”的计时器并输出

3、定義函數 
在Node.js中定義函數的辦法與普通JavaScript中完全相同,不過我們推薦的寫法如下,即使用一個變數為函數命名,這樣可以比較方便明確的將函數作為參數傳遞給其他函數: 

//定义一个名为showErr的函数 
var showErr=function(msg){ 
var inf="错误!"+msg; 
console.log(inf+msg); 
return msg; 
}

4、建立Web伺服器並偵聽存取請求 
建立Web伺服器最重要的是提供Web請求的回應函數,它有兩個參數,第一個代表客戶端請求的訊息,另一個代表將要傳回給客戶端的訊息。在回應函數中應解析請求訊息,依據請求,組裝返後內容。

//请求模块 
var libHttp = require('http'); //HTTP协议模块 
//Web服务器主函数,解析请求,返回Web内容 
var funWebSvr = function (req, res){ 
res.writeHead(200, {'Content-Type': 'text/html'}); 
res.write(&#39;<html><body>&#39;); 
res.write(&#39;<h1>*** Node.js ***</h1>&#39;); 
res.write(&#39;<h2>Hello!</h2>&#39;); 
res.end(&#39;</body></html>&#39;); 
} 
//创建一个http服务器 
var webSvr=libHttp.createServer(funWebSvr); 
//开始侦听8124端口 
webSvr.listen(8124);

5、解析Web請求 
對於簡單的Web網頁存取請求,重要的資訊包含在請求資訊參數的url裡,我們可以使用url解析模組解析url中的存取路徑,並利用path模組,將存取路徑組裝為要存取的實際檔案路徑用於返回。 

var reqUrl=req.url; //获取请求的url 
//向控制台输出请求的路径 
console.log(reqUrl); 
//使用url解析模块获取url中的路径名 
var pathName = libUrl.parse(reqUrl).pathname; 
//使用path模块获取路径名中的扩展名 
if (libPath.extname(pathName)=="") { 
//如果路径没有扩展名 
pathName+="/"; //指定访问目录 
} 
if (pathName.charAt(pathName.length-1)=="/"){ 
//如果访问目录 
pathName+="index.html"; //指定为默认网页 
} 
//使用路径解析模块,组装实际文件路径 
var filePath = libPath.join("./WebRoot",pathName);

6、設定回傳頭 
由於是Web請求,需要在回傳內容中包含http回傳頭,這裡重點是依據要存取的檔案路徑的檔案副檔名,設定http回傳頭的內容類型。 

var contentType=""; 
//使用路径解析模块获取文件扩展名 
var ext=libPath.extname(filePath); 
switch(ext){ 
case ".html": 
contentType= "text/html"; 
break; 
case ".js": 
contentType="text/javascript"; 
break; 
... 
... 
default: 
contentType="application/octet-stream"; 
} 
//在返回头中写入内容类型 
res.writeHead(200, {"Content-Type": contentType });

7、寫入回傳物件中寫入存取的檔案內容 
有了需要存取的檔案實際路徑,有了檔案對應的內容類型,就可以利用fs檔案系統模組讀取檔案流並傳回給客戶端。

//判断文件是否存在 
libPath.exists(filePath,function(exists){ 
if(exists){//文件存在 
//在返回头中写入内容类型 
res.writeHead(200, {"Content-Type": funGetContentType(filePath) }); 
//创建只读流用于返回 
var stream = libFs.createReadStream(filePath, {flags : "r", encoding : null}); 
//指定如果流读取错误,返回404错误 
stream.on("error", function() { 
res.writeHead(404); 
res.end("<h1>404 Read Error</h1>"); 
}); 
//连接文件流和http返回流的管道,用于返回实际Web内容 
stream.pipe(res); 
} 
else { //文件不存在 
//返回404错误 
res.writeHead(404, {"Content-Type": "text/html"}); 
res.end("<h1>404 Not Found</h1>"); 
} 
});

二、測試及運行 
1、完整原始碼 
以下100行左右的JavaScript就是建立這樣一個簡單web伺服器的全部原始碼: 

//------------------------------------------------ 
//WebSvr.js 
// 一个演示Web服务器 
//------------------------------------------------ 
//开始服务启动计时器 
console.time('[WebSvr][Start]'); 
//请求模块 
var libHttp = require('http'); //HTTP协议模块 
var libUrl=require('url'); //URL解析模块 
var libFs = require("fs"); //文件系统模块 
var libPath = require("path"); //路径解析模块 
//依据路径获取返回内容类型字符串,用于http返回头 
var funGetContentType=function(filePath){ 
var contentType=""; 
//使用路径解析模块获取文件扩展名 
var ext=libPath.extname(filePath); 
switch(ext){ 
case ".html": 
contentType= "text/html"; 
break; 
case ".js": 
contentType="text/javascript"; 
break; 
case ".css": 
contentType="text/css"; 
break; 
case ".gif": 
contentType="image/gif"; 
break; 
case ".jpg": 
contentType="image/jpeg"; 
break; 
case ".png": 
contentType="image/png"; 
break; 
case ".ico": 
contentType="image/icon"; 
break; 
default: 
contentType="application/octet-stream"; 
} 
return contentType; //返回内容类型字符串 
} 
//Web服务器主函数,解析请求,返回Web内容 
var funWebSvr = function (req, res){ 
var reqUrl=req.url; //获取请求的url 
//向控制台输出请求的路径 
console.log(reqUrl); 
//使用url解析模块获取url中的路径名 
var pathName = libUrl.parse(reqUrl).pathname; 
if (libPath.extname(pathName)=="") { 
//如果路径没有扩展名 
pathName+="/"; //指定访问目录 
} 
if (pathName.charAt(pathName.length-1)=="/"){ 
//如果访问目录 
pathName+="index.html"; //指定为默认网页 
} 
//使用路径解析模块,组装实际文件路径 
var filePath = libPath.join("./WebRoot",pathName); 
//判断文件是否存在 
libPath.exists(filePath,function(exists){ 
if(exists){//文件存在 
//在返回头中写入内容类型 
res.writeHead(200, {"Content-Type": funGetContentType(filePath) }); 
//创建只读流用于返回 
var stream = libFs.createReadStream(filePath, {flags : "r", encoding : null}); 
//指定如果流读取错误,返回404错误 
stream.on("error", function() { 
res.writeHead(404); 
res.end("<h1>404 Read Error</h1>"); 
}); 
//连接文件流和http返回流的管道,用于返回实际Web内容 
stream.pipe(res); 
} 
else { //文件不存在 
//返回404错误 
res.writeHead(404, {"Content-Type": "text/html"}); 
res.end("<h1>404 Not Found</h1>"); 
} 
}); 
} 
//创建一个http服务器 
var webSvr=libHttp.createServer(funWebSvr); 
//指定服务器错误事件响应 
webSvr.on("error", function(error) { 
console.log(error); //在控制台中输出错误信息 
}); 
//开始侦听8124端口 
webSvr.listen(8124,function(){ 
//向控制台输出服务启动的信息 
console.log('[WebSvr][Start] running at http://127.0.0.1:8124/'); 
//结束服务启动计时器并输出 
console.timeEnd('[WebSvr][Start]'); 
});

2、資源目錄

   WebRoot目錄來存放實際的網頁和圖片資源,「WebRoot」的目錄名稱在上述原始碼中被用來組裝實際檔案路徑。

Node.js实战 建立简单的Web服务器

3、運行並測試

    在命令列中輸入:

node.exe WebSvr.js

   我們的WebWebSvr.js

Node.js实战 建立简单的Web服务器   我們的WebWeb運作效果如下:

 後記

    利用Node.js我們可以方便建立相對獨立的Web伺服器,其事件驅動的特性避免繁瑣的執行緒開發,其基礎模組更降低了困難度。本章建立的Web伺服器只是一個簡單的樣本,沒有太多考慮的模組化、安全性等問題,但可以從中掌握Node.js開發的一些基本的知識。


更多Node.js實戰 建立簡單的Web伺服器相關文章請關注PHP中文網!

🎜🎜🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn