操作fs模塊 const path = require("path"); const fs = require("fs"); /* 相對路徑是命令視窗執行的目錄 node 提供了path模塊來操作路徑相關的api, 其中__dirname是一個內置的變數,返回當前文件所在的目錄 */ const g ...
操作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 註入進來。
執行第一個中間件的fn,調用next 進入到下一個中間件,繼續執行下一個fn,調用next 友進入下一個中間件,繼續重覆上述邏輯,直至最後一個中間件,直至最後一個中間件,就會執行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 入門基本也結束了。