2021-05-12 14:32:11
極簡 Node.js 入門
極簡 Node.js 入門系列教學:https://www.yuque.com/sunluyong/node
使用 Node.js 建立 http 伺服器需要使用內建的 http
模組
建立 web server
Node.js 是執行在伺服器環境的 JavaScript,這裡的伺服器更多指的是物理概念的伺服器,也就是主機。使用 Node.js 建立 HTTP 伺服器指的是軟體概念的伺服器,也就是 web server,類似於 nginx、apache
const http = require('http');
const server = http.createServer((req, res) => {
res.write('Hellon');
res.end();
});
server.listen(9527, () => {
console.log('Web Server started at port 9527');
});
上面 10 行程式碼建立了一個最簡單的 HTTP 伺服器,伺服器監聽埠號 9527,接收到請求後返回字串 Hellon
,可以使用瀏覽器或者 curl 工具測試
createServer 的回撥函數在接收到請求後被呼叫
req
req 代表本次 http request,是一個可讀流,常用有幾個屬性
res
res 代表本次http response,是一個可寫流,常用的屬性方法有
- writeHead(statusCode,[, StatusMessage[, headers]]):傳送響應首部,包含狀態碼、狀態資訊、響應頭
- write(chunk):向響應主體中寫入字串或者 buffer
- end(chunk):向伺服器發出訊號,可以攜帶最後傳送的資料,表明已傳送所有響應頭和主體,每個響應都需要呼叫一次
- getHeader(name):返回指定 name 的 header
- getHeaders():返回包含了所有 header 資訊的物件
- setHeader(name, value):設定響應頭,和 writeHead() 合併,有衝突時優先使用 writeHead()
- statusCode:設定響應 HTTP status
返回請求資訊的 web server
上面例子中所有請求返回的結果都一樣,可以對請求識別,做一些差異化的處理,下面例子展示瞭如何把每次請求的基本資訊返回
const http = require('http');
const server = http.createServer((req, res) => {
const { url, method, headers } = req;
res.setHeader('content-type', 'text/html');
res.write(`請求 URL: ${url}n`);
res.write(`請求方法: ${method}n`);
res.write(`請求 headers:${JSON.stringify(headers, null, ' ')}`);
res.end('n');
});
server.listen(9527, () => {
console.log('Web Server started at port 9527');
});
返回檔案內容
上面例子和真實的 web server 還有很大差距,下面例子展示了一個最簡單的返回檔案內容的靜態資源伺服器
const http = require('http');
const path = require('path');
const fs = require('fs');
const mime = require('mime-types');
// 靜態資源根目錄,可以設定為原生的任意有許可權目錄,放入 a.jpg 測試
const ROOT_DIRECTORY = '/public';
const server = http.createServer((req, res) => {
const { url } = req;
const filePath = path.join(ROOT_DIRECTORY, url);
fs.readFile(filePath, (err, chunk) => {
if (err) {
res.writeHead(404, {
'content-type': 'text/html',
});
res.end('檔案不存在!');
} else {
res.writeHead(200, {
'content-type': mime.contentType(path.extname(url)),
});
res.end(chunk);
}
});
});
server.listen(9527, () => {
console.log('Web Server started at port 9527');
});
demo 中使用了 mime-types 包來根據檔名稱獲取檔案的 Content-Type,執行 demo 需要在程式碼目錄安裝 mime-types
tnpm i -S mime-types
- 200 OK,表示請求正常處理
- 404 Not Found,表示請求資源在伺服器不存在
在測試目錄下放入圖片 a.jpg
使用瀏覽器測試 127.0.0.1:9527/a.jpg
讀取電影檔案
理論上讀取電影檔案可以使用和上面一樣的程式碼,但實際執行會發現電影檔案在完全讀取到記憶體後才返回給瀏覽器,這樣返回內容耗時極長,而且電影檔案過大的話程式也沒有辦法處理,HTTP 協定是支援分段傳輸的(Transfer-Encoding: chunked),既然 res 是可寫流,可以簡單使用 stream 來做到邊讀取內容邊返回給瀏覽器,而不是一次讀取完成後返回
const http = require('http');
const path = require('path');
const fs = require('fs');
const mime = require('mime-types');
// 靜態資源根目錄
const ROOT_DIRECTORY = '/Users/undefined/node-demo/public';
const server = http.createServer((req, res) => {
const { url } = req;
const filePath = path.join(ROOT_DIRECTORY, url);
fs.access(filePath, fs.constants.R_OK, err => {
if (err) {
res.writeHead(404, {
'content-type': 'text/html',
});
res.end('檔案不存在!');
} else {
res.writeHead(200, {
'content-type': mime.contentType(path.extname(url)),
});
fs.createReadStream(filePath).pipe(res);
}
});
});
server.listen(9527, () => {
console.log('Web Server started at port 9527');
});
使用 stream 章節介紹的 fs.createReadStream() 和 pipe() 可以輕鬆將檔案匯入 http response
Node.js 官網一次 HTTP 傳輸解析對 HTTP Server 做了入門講解,順便介紹了一些 HTTP 協定的相關知識,值得閱讀
相關文章