1. 程式人生 > >Node.js之http模組

Node.js之http模組

Node.js開發的目的就是為了用JavaScript編寫Web伺服器程式。因為JavaScript實際上已經統治了瀏覽器端的指令碼,其優勢就是有世界上數量最多的前端開發人員。如果已經掌握了JavaScript前端開發,再學習一下如何將JavaScript應用在後端開發,就是名副其實的全棧了。

HTTP協議

要理解Web伺服器程式的工作原理,首先,我們要對HTTP協議有基本的瞭解。如果你對HTTP協議不太熟悉,先看一看HTTP協議簡介。

HTTP伺服器

要開發HTTP伺服器程式,從頭處理TCP連線,解析HTTP是不現實的。這些工作實際上已經由Node.js自帶的http模組完成了。應用程式並不直接和HTTP協議打交道,而是操作http

模組提供的requestresponse物件。

request物件封裝了HTTP請求,我們呼叫request物件的屬性和方法就可以拿到所有HTTP請求的資訊

response物件封裝了HTTP響應,我們操作response物件的方法,就可以把HTTP響應返回給瀏覽器。

用Node.js實現一個HTTP伺服器程式非常簡單。我們來實現一個最簡單的Web程式hello.js,它對於所有請求,都返回Hello world!

'use strict';
var http = require('http');// 匯入http模組

// 建立http server,並傳入回撥函式。回撥函式接收request和response物件
var server = http.createServer(function (request, response){
console.log(request.method + ': ' + request.url);// 獲得HTTP請求的method和url:
response.writeHead(200, {'Content-Type': 'text/html'});// 將HTTP響應200寫入response, 同時設定Content-Type: text/html
response.end('<h1>Hello world!</h1>'); });// 將HTTP響應的HTML內容寫入response
server.listen(8080); // 讓伺服器監聽8080埠

console.log('Server is running at http://127.0.0.1:8080/');

在命令提示符下執行該程式,可以看到以下輸出:

$ node hello.js Server is running at http://127.0.0.1:8080/

不要關閉命令提示符,直接開啟瀏覽器輸入http://localhost:8080,即可看到伺服器響應的內容:

                                              

同時,在命令提示符視窗,可以看到程式列印的請求資訊:

GET: /

GET: /favicon.ico

這就是我們編寫的第一個HTTP伺服器程式!

檔案伺服器

讓我們繼續擴充套件一下上面的Web程式。我們可以設定一個目錄,然後讓Web程式變成一個檔案伺服器。要實現這一點,我們只需要解析request.url中的路徑,然後在本地找到對應的檔案,把檔案內容傳送出去就可以了。

解析URL需要用到Node.js提供的url模組,它使用起來非常簡單,通過parse()將一個字串解析為一個Url物件:

'use strict';
var url = require('url');

console.log(url.parse('http://user:[email protected]:8080/path/to/file?query=string#hash'));

結果如下:

Url {
 protocol: 'http:',  slashes: true,  auth: 'user:pass',  host: 'host.com:8080',  port: '8080',  hostname: 'host.com',  hash: '#hash',  search: '?query=string',  query: 'query=string',  pathname: '/path/to/file',  path: '/path/to/file?query=string',  href: 'http://user:[email protected]:8080/path/to/file?query=string#hash' }

處理本地檔案目錄需要使用Node.js提供的path模組,它可以方便地構造目錄:

'use strict';
var path = require('path');
var workDir = path.resolve('.');// 解析當前目錄('/Users/michael')
var filePath = path.join(workDir, 'pub', 'index.html');// 組合完整的檔案路徑:當前目錄+'pub'+'index.html'('/Users/michael/pub/index.html')

使用path模組可以正確處理作業系統相關的檔案路徑。在Windows系統下,返回的路徑類似於C:\Users\michael\static\index.html,這樣,我們就不關心怎麼拼接路徑了。

最後,我們實現一個檔案伺服器file_server.js

'use strict';
var  fs = require('fs'),url = require('url'),path = require('path'),http = require('http');
var root = path.resolve(process.argv[2] || '.');// 從命令列引數獲取root目錄,預設是當前目錄
console.log('Static root dir: ' + root);
var server = http.createServer(function (request, response){// 建立伺服器
var pathname = url.parse(request.url).pathname;// 獲得URL的path,類似 '/css/bootstrap.css'
var filepath = path.join(root, pathname);// 獲得對應的本地檔案路徑,類似 '/srv/www/css/bootstrap.css'
fs.stat(filepath, function (err, stats) {if (!err && stats.isFile()) {// 獲取檔案狀態
console.log('200 ' + request.url);// 沒有出錯並且檔案存在
response.writeHead(200);// 傳送200響應
// 將檔案流導向response:
fs.createReadStream(filepath).pipe(response);    

} else {
console.log('404 ' + request.url);// 出錯了或者檔案不存在
response.writeHead(404); response.end('404 Not Found'); }  }); }); // 傳送404響應

server.listen(8080);

console.log('Server is running at http://127.0.0.1:8080/');

沒有必要手動讀取檔案內容。由於response物件本身是一個Writable Stream,直接用pipe()方法就實現了自動讀取檔案內容並輸出到HTTP響應。

在命令列執行node file_server.js /path/to/dir,把/path/to/dir改成你本地的一個有效的目錄,然後在瀏覽器中輸入http://localhost:8080/index.html

                                       

 

只要當前目錄下存在檔案index.html,伺服器就可以把檔案內容傳送給瀏覽器。觀察控制檯輸出:

200 /index.html

200 /css/uikit.min.css

200 /js/jquery.min.js

200 /fonts/fontawesome-webfont.woff2

第一個請求是瀏覽器請求index.html頁面,後續請求是瀏覽器解析HTML後傳送的其它資源請求。

練習

在瀏覽器輸入http://localhost:8080/時,會返回404,原因是程式識別出HTTP請求的不是檔案,而是目錄。請修改file_server.js;如果遇到請求的路徑是目錄,則自動在目錄下依次搜尋index.htmldefault.html,如果找到了,就返回HTML檔案的內容。

參考原始碼

http伺服器程式碼(含靜態網站)

https://github.com/michaelliao/learn-javascript/tree/master/samples/node/http