操作fs模組
const path = require("path");
const fs = require("fs");
/*
相對路徑是命令視窗執行的目錄
node 提供了path模組來操作路徑相關的api, 其中__dirname是一個內建的變數,返回當前檔案所在的目錄
*/
const getDirUrl = dir => {
return path.resolve(__dirname, dir);
};
for (let i = 0; i < 5; i++) {
fs.writeFileSync(getDirUrl("./create01.text"), i + "、我是測試資料" + i + "\n", {
flag: "a+",
encoding: "utf-8"
});
}
console.log("hello nodejs");
const data = fs.readFileSync(getDirUrl("./create01.text"), {encoding: 'utf-8'}).toString()
console.log('同步讀取')
console.log(data)
console.log('非同步讀取')
fs.readFile(getDirUrl("./create01.text"), (err, data) => {
if(!err) {
console.log(data.toString());
} else {
console.error(err);
}
});
在視窗執行對應的目錄即可,我這裡是:
操作http模組
// 1. 匯入http模組
const http = require("http");
const fs = require("fs");
const path = require("path");
const mimes = {
html: "text/html",
css: "text/css",
js: "text/javascript",
png: "image/png",
jpg: "image/jpeg",
gif: "image/gif",
mp4: "video/mp4",
mp3: "audio/mpeg",
json: "application/json"
};
//2. 建立服務物件 create 建立 server 服務
// request 意為請求. 是對請求報文的封裝物件, 透過 request 物件可以獲得請求報文的資料
// response 意為響應. 是對響應報文的封裝物件, 透過 response 物件可以設定響應報文
const server = http.createServer((req, res) => {
let { url, method } = req;
// 資料夾路徑
const rootDir = __dirname + "/public";
let filePath = rootDir + url;
if (!fs.existsSync(filePath)) {
return
}
// 讀取內容
fs.readFile(filePath, (err, data) => {
if (err) {
console.log(err);
//設定字符集
res.setHeader('content-type','text/html;charset=utf-8');
//判斷錯誤的代號
switch(err.code){
case 'ENOENT':
res.statusCode = 404;
res.end('<h1>404 Not Found</h1>');
case 'EPERM':
res.statusCode = 403;
res.end('<h1>403 Forbidden</h1>');
default:
res.statusCode = 500;
res.end('<h1>500 Internal Server Error</h1>');
}
return;
}
//獲取檔案的字尾名
let ext = path.extname(filePath).slice(1);
//獲取對應的型別
let type = mimes[ext];
if(type){
if(ext === 'html'){
res.setHeader('content-type', type + ';charset=utf-8');
}else{
res.setHeader('content-type', type);
}
}else{
//沒有匹配到-預設設定二進位制檔案型別
res.setHeader('content-type', 'application/octet-stream');
}
//響應檔案內容
res.end(data);
});
});
//3. 監聽埠, 啟動服務
server.listen(9000, () => {
console.log("服務已經啟動,9000埠監聽中...");
});
如上最簡單的http 服務起來了,在瀏覽器中 輸入 http://localhost:9000/index.html 得到如下頁面
透過匹配字尾,在public檔案中返回對應的資源,程式碼結構如下
都是一些很簡單的程式碼就不貼了,如果需要留下郵箱
即可。
其他模組看看官網的文件即可,不在記錄。
框架
上面都是透過原始的方式來使用node,其實node的生態也很豐富,有很多的框架讓我們選擇,如 express、koa2、nestjs、midwayjs 等等
express 基本使用
// 1.0 匯入express
const express = require('express')
// 2.0 express 例項
const app = express()
const port = 9000
// 3.0 路由
app.get('/', (req, res) => {
res.send('基本使用 Hello World!')
})
// 啟動服務
app.listen(port, () => {
console.log(`啟動服務,埠: ${port}`)
})
通常我們使用腳手架,這樣可以得到統一的專案結構 如 express_ generator,具體檢視express 官網
中介軟體-洋蔥模型
目前比較流行的 nodejs http 服務框架使用攔截器模式,這種模式將 http 請求響應的過程分為若干切面,每個切面上進行一項或若干項關聯的操作。比如說,我們可以透過不同的攔截切面處理使用者資訊驗證、會話(session)驗證、表單資料驗證、query 解析,或者業務邏輯處理等等。這種架構設計讓切面與切面之間彼此獨立。
有點面向切面程式設計的概念,不知道對不對。
手動實現一個攔截器:實現類似如下效果
async (ctx, next) => {
do sth...
}
透過呼叫next
執行下一個函式,可以中途return
退出,也可以繼續呼叫next
直到最後一個函式,然後在一層一層的返回,洋蔥的結構跟這個類似,所以叫洋蔥模型。
這裡的中介軟體其實是一個函式,在外層使用use 注入進來。
next
語句後面的程式碼,然後繼續上一個中介軟體的next
後置語句,繼續重複上述邏輯,直至執行第一個中介軟體的next
後置語句,最後輸出,這個執行的機制,稱為洋蔥模型
。模擬洋蔥模型
洋蔥模型關鍵在於怎麼處理next 引數,next是下一個函式的引用, ,可以透過我們索引加閉包,或者累加器的形式來處理,為了方便直接使用累加器的形式即可,如下程式碼:
/*
這個思路透過利用累加器函式的特性,返回一個函式
*/
class Interceptor {
aspects = [];
use (fn) {
this.aspects.push(fn)
return this
}
async run (context) {
// 從右往左開始遍歷
const proc = this.aspects.reduceRight(
function (a, b) {
let flag = false
return async () => {
// a 上一個fn,也就是呼叫的時傳入的 next
if (flag) {
return
}
flag = true
await b(context, a)
}
},() => Promise.resolve())
try {
// 透過這個reduceRight 讓函式串起來了
await proc()
} catch (e) {
console.error(e);
}
}
}
// 測試
const inter = new Interceptor()
inter.use(function a(context, next) {
console.log("a");
next();
console.log("a_after");
});
inter.use(function b(context, next) {
console.log("b");
next();
console.log("b_after");
});
inter.use(function c(context, next) {
console.log("c");
next();
console.log("c_after");
});
inter.use(function d(context, next) {
console.log("d");
next();
console.log("d_after");
});
inter.run();
輸出a、b、c、d、d_after、c_after、b_after、a_after 其中koa2 原始碼中使用了索引加閉包的形式來處理 原始碼
小結
理解了nodejs 寫起來還是挺順手的,官網文件也還好。至於其他如sql
、路由
、保持會話狀態
等後臺基本知識點,看看相關文件即可,並沒有什麼難度。
nodejs 入門基本也結束了。