聊聊怎麼使用Node.js建立一個簡單的HTTP伺服器

2022-06-27 14:02:11
怎麼使用NodeJS建立HTTP伺服器?下面本篇文章給大家介紹一下使用建立一個簡單的HTTP伺服器的方法,希望對大家有所幫助!

1. 使用Node.js直接執行JavaScript指令碼

基於Chromev8引擎執行js程式碼,因此我們可以擺脫瀏覽器環境,直接在控制檯中執行js程式碼,比如下面這個hello world程式碼

console.log('hello world');

控制檯中直接使用node即可執行

1.png


2. 建立一個簡單的HTTP伺服器

node.js的內建模組http提供了基本的http服務的能力,基於CommonJS規範,我們可以使用require匯入http模組進行使用http模組中有一個createServer函數能夠讓我們建立一個http伺服器 其接收一個回撥函數作為引數,這個回撥函數接收兩個引數 -- requestresponse

  • request包括所有使用者端請求的資訊,比如url、請求頭header、請求方式和請求體等
  • response主要用於返回資訊給使用者端,封裝了一些操作響應體相關的操作,比如response.writeHead方法就可以讓我們自定義返回體的頭部資訊和狀態碼

當我們將響應體處理好了之後,呼叫response.end()方法就可以將響應體傳送給使用者端 使用createServer函數只是幫我們建立了一個Server物件,並沒有讓其開啟監聽,我們還需要呼叫server物件的listen方法才可以進行監聽,真正作為一個伺服器開始執行

  • listen方法的第一個引數是監聽的埠號,第二個引數則是繫結的主機ip,第三個引數是一個回撥函數,會被http模組非同步呼叫,當遇到錯誤的時候,就能夠在這個回撥函數的第一個引數中獲取到丟擲的異常 ,我們可以選擇對異常進行處理,讓我們的伺服器更加健壯

下面是使用http模組建立一個簡單伺服器的例子

const { createServer } = require('http');
const HOST = 'localhost';
const PORT = '8080';

const server = createServer((req, resp) => {
  // the first param is status code it returns  
  // and the second param is response header info
  resp.writeHead(200, { 'Content-Type': 'text/plain' });  
  
  console.log('server is working...');  
  
  // call end method to tell server that the request has been fulfilled
  resp.end('hello nodejs http server');
});

server.listen(PORT, HOST, (error) => {  
if (error) {  
  console.log('Something wrong: ', error);   
   return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

可以直接嘗試用node執行它,創造一個屬於你的伺服器!伺服器執行後,瀏覽器存取http://localhost:8080即可存取到這個伺服器

2.png

也可以使用nodemon執行它,這樣當我們的程式碼發生變化的時候就不需要手動終止程式再重新執行了

npm i -g nodemon

建議全域性安裝它,這樣就可以直接使用,不需要通過npx nodemon去使用 使用也很簡單,直接將node命令改成nodemon命令即可

nodemon http-server.js

3.png


3. 加上型別提示

前面我們在使用createServer以及resp物件的時候,看不到任何的語法提示,必須隨時跟著node官方檔案去邊用邊查,有點不方便 但是沒關係,我們可以使用ts.d.ts檔案幫助我們提供語法提示功能,注意,我們不是使用ts進行開發,只是使用它的語法提示功能而已

  1. 初始化專案 -- npm init -y
  2. 安裝@types/node -- pnpm i @types/node -D
  3. 在專案目錄下建立jsconfig.json檔案,將node_modules排除在外,沒必要對其進行檢查
{  "compilerOptions": {
    "checkJs": true
  },  
  "exclude": ["node_modules", "**/node_modules/*"]
}

不知道你是否有發現上面的程式碼其實是有一處錯誤的呢?checkJs能夠幫助我們檢查型別錯誤問題,可以根據需要選擇是否開啟 可以看到,開啟檢查後立馬就給我們提示了引數型別不匹配的問題

4.png

這時候將滑鼠懸浮在listen方法上,就能夠看到該方法的簽名

5.png

可以看到,原來port引數需要是number型別,但是我們定義的時候是string型別,所以沒匹配上,將其修改為number8080即可 而且可以直接檢視到相關api的檔案,不需要開啟node官方的檔案找半天去檢視了


4. 返回多個字串的響應體

前面我們的簡單http server中只返回了一句話,那麼是否能夠返回多句話呢? 這就要用到resp物件的write方法了,end只能夠返回一次內容,而是用write方法,我們可以多次寫入內容到響應體中,最後只用呼叫一次end,並且不傳遞任何引數,只讓他完成傳送響應體的功能

const { createServer } = require("http");
const HOST = "localhost";
const PORT = 8080;

const server = createServer((req, resp) => {
  resp.writeHead(200, { "Content-Type": "text/plain" });  
  console.log("server is working...");  
  
  // write some lorem sentences
  resp.write("Lorem ipsum dolor sit amet consectetur adipisicing elit.\n");
  resp.write("Omnis eligendi aperiam delectus?\n");
  resp.write("Aut, quam quo!\n");

  resp.end();
});

server.listen(PORT, HOST, (error) => {
  if (error) {    
  console.log("Something wrong: ", error);    
  return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

這次我們寫入了三句話,現在的效果就變成這樣啦

6.png


5. 返回html

我們不僅可以返回字串給瀏覽器,還可以直接讀取html檔案的內容並將其作為結果返回給瀏覽器 這就需要用到另一個Node.js的內建模組 -- fs,該模組提供了檔案操作的功能 使用fs.readFile可以非同步進行讀取檔案的操作,但是它不會返回promise物件,因此我們需要傳入回撥去處理讀取到檔案後的操作 還可以使用fs.readFileSync進行同步阻塞讀取檔案,這裡我們選擇非同步讀取

const { createServer } = require("http");
const fs = require("fs");
const HOST = "localhost";

const PORT = 8080;const server = createServer((req, resp) => {
  // change the MIME type from text/plain to text/html
  resp.writeHead(200, { "Content-Type": "text/html" });  
  
  // read the html file content
  fs.readFile("index.html", (err, data) => { 
     if (err) {  
      console.error(      
        "an error occurred while reading the html file content: ",
        err
      );      throw err;
    }    
    console.log("operation success!");

    resp.write(data);
    resp.end();
  });
});

server.listen(PORT, HOST, (error) => {
  if (error) {    
  console.log("Something wrong: ", error);    
  return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

現在的結果就像下面這樣:

7.png

成功將html返回注意:這裡需要將響應頭的**Content-Type**改為**text/html**,告知瀏覽器我們返回的是**html**檔案的內容,如果仍然以**text/plain**返回的話,瀏覽器不會對返回的內容進行解析,即便它是符合**html**語法的也不會解析,就像下面這樣:

8.png


6. 返回JSON

當我們需要編寫一個後端伺服器,只負責返回介面資料的時候,就需要返回json格式的內容了,相信聰明的你也知道該怎麼處理了:

  1. MIME型別設定為application/json
  2. resp.write的時候傳入的是json字串,可以使用JSON.stringify處理物件後返回
const { createServer } = require("http");
const HOST = "localhost";
const PORT = 8080;

const server = createServer((req, resp) => { 
 // change the MIME type to application/json
  resp.writeHead(200, { "Content-Type": "application/json" });  
  
  // create a json data by using an object  
  const jsonDataObj = {
      code: 0,    
      message: "success",    
      data: {  
          name: "plasticine",      
          age: 20,      
          hobby: "coding",
    },
  };

  resp.write(JSON.stringify(jsonDataObj));
  resp.end();
});

server.listen(PORT, HOST, (error) => {
  if (error) { 
     console.log("Something wrong: ", error);    
     return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

結果如下:

9.png


7. 返回pdf檔案

和之前返回html檔案的思路類似,都是一個設定響應頭MIME型別,讀取檔案,返回檔案內容的過程 但是這次我們搞點不一樣的 我們的思路是在伺服器執行的時候生成一個pdf檔案,並將它返回 還需要將MIME的型別改為application/pdf生成pdf檔案需要用到一個庫 -- pdfkit

pnpm i pdfkit

首先我們編寫一個建立pdf檔案的函數,因為建立pdf檔案還需要進行一些寫入操作,不確定什麼時候會完成,但是我們的請求必須等到pdf檔案建立完成後才能得到響應 所以我們需要將它變成非同步進行的,返回一個promise

/**
 * @description 建立 pdf 檔案
 */const createPdf = () => {
   return new Promise((resolve, reject) => {
       if (!fs.existsSync("example.pdf")) {      
       // create a PDFDocument object      
       const doc = new PDFDocument();
       
       // create write stream by piping the pdf content.
       doc.pipe(fs.createWriteStream("example.pdf"));   
        
      // add some contents to pdf document
      doc.fontSize(16).text("Hello PDF", 100, 100);   
         
      // complete the operation of generating PDF file.
      doc.end();
    }

    resolve("success");
  });
};

這裡使用到了管道操作,將PDFDocument物件的內容通過管道傳到新建立的寫入流中,當完成操作後我們就通過resovle告知外界已經建立好pdf檔案了 然後在伺服器端程式碼中呼叫

const server = createServer(async (req, resp) => {
  // change the MIME type to application/pdf
  resp.writeHead(200, { "Content-Type": "application/pdf" });  
  
  // create pdf file  
  await createPdf();  
  
  // read created pdf file
  fs.readFile("example.pdf", (err, data) => {
      if (err) { 
       console.error(        
        "an error occurred while reading the pdf file content: ",
        err
      );      
      throw err;
    }    
    console.log("operation success!");

    resp.end(data);
  });
});

server.listen(PORT, HOST, (error) => {
  if (error) {
      console.log("Something wrong: ", error);    
      return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

現在瀏覽器就可以讀取到建立的pdf檔案了

10.png


8. 返回音訊檔

思路依然是一樣的,讀取一個音訊檔,然後通過管道將它送到resp物件中再返回即可

const { createServer } = require("http");
const { stat, createReadStream } = require("fs");
const HOST = "localhost";
const PORT = 8080;

const server = createServer((req, resp) => {
  // change the MIME type to audio/mpe
  resp.writeHead(200, { "Content-Type": "audio/mp3" });  
  const mp3FileName = "audio.mp3";

  stat(mp3FileName, (err, stats) => {
    if (stats.isFile()) {      
      const rs = createReadStream(mp3FileName);      
      
      // pipe the read stream to resp
      rs.pipe(resp);
    } else {
      resp.end("mp3 file not exists");
    }
  });
});

server.listen(PORT, HOST, (error) => {
  if (error) {    
  console.log("Something wrong: ", error);    
  return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

效果如下

11.png

開啟後就是一個播放音訊的介面,這是chrome提供的對音訊檔的展示,並且開啟控制檯會發現有返回音訊檔

11-2.png

注意:將音訊檔流通過管道傳到**resp**後,不需要呼叫**resp.end()**方法,因為這會關閉整個響應,導致音訊檔無法獲取

12.png

13.png


9. 返回視訊檔

視訊檔和音訊檔的處理是一樣的,只是MIME的型別要改成video/mp4,其他都一樣

const { createServer } = require("http");
const { stat, createReadStream } = require("fs");
const HOST = "localhost";
const PORT = 8080;
const server = createServer((req, resp) => {  
// change the MIME type to audio/mpe
  resp.writeHead(200, { "Content-Type": "audio/mp4" });  
  const mp4FileName = "video.mp4";

  stat(mp4FileName, (err, stats) => { 
     if (stats.isFile()) {      
     const rs = createReadStream(mp4FileName);      
     // pipe the read stream to resp
      rs.pipe(resp);
    } else {
      resp.end("mp4 file not exists");
    }
  });
});

server.listen(PORT, HOST, (error) => { 
 if (error) {    
 console.log("Something wrong: ", error);    
 return;
  }  
  console.log(`server is listening on http://${HOST}:${PORT} ...`);
});

14.png


總結

我們學會了:

  • 如何使用Node建立一個http伺服器
  • js加上型別提示
  • 如何返回字串響應體
  • 如何返回html
  • 如何返回JSON
  • 如何生成並返回pdf檔案
  • 如何返回音訊檔
  • 如何返回視訊檔

雖然內容簡單,但還是希望你能跟著動手敲一敲,不要以為簡單就看看就算了,看了不代表會了,真正動手實現過後才會找到自己的問題

更多node相關知識,請存取:!

以上就是聊聊怎麼使用Node.js建立一個簡單的HTTP伺服器的詳細內容,更多請關注TW511.COM其它相關文章!