nodejs 入門基本操作

操作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 入門基本也結束了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章