怎么使用NodeJS創(chuàng)建HTTP服務(wù)器?下面本篇文章給大家介紹一下使用Node創(chuàng)建一個(gè)簡(jiǎn)單的HTTP服務(wù)器的方法,希望對(duì)大家有所幫助!
node.js極速入門(mén)課程:進(jìn)入學(xué)習(xí)
1. 使用Node.js直接運(yùn)行JavaScript腳本
node.js
基于Chrome
的v8
引擎運(yùn)行js
代碼,因此我們可以擺脫瀏覽器環(huán)境,直接在控制臺(tái)中運(yùn)行js
代碼,比如下面這個(gè)hello world
代碼
console.log('hello world');
控制臺(tái)中直接使用node
即可運(yùn)行
2. 創(chuàng)建一個(gè)簡(jiǎn)單的HTTP服務(wù)器
node.js
的內(nèi)置模塊http
提供了基本的http
服務(wù)的能力,基于CommonJS
規(guī)范,我們可以使用require
導(dǎo)入http
模塊進(jìn)行使用http
模塊中有一個(gè)createServer
函數(shù)能夠讓我們創(chuàng)建一個(gè)http
服務(wù)器 其接收一個(gè)回調(diào)函數(shù)作為參數(shù),這個(gè)回調(diào)函數(shù)接收兩個(gè)參數(shù) — request
和response
?!鞠嚓P(guān)教程推薦:nodejs視頻教程】
request
包括所有客戶端請(qǐng)求的信息,比如url
、請(qǐng)求頭header
、請(qǐng)求方式和請(qǐng)求體等response
主要用于返回信息給客戶端,封裝了一些操作響應(yīng)體相關(guān)的操作,比如response.writeHead
方法就可以讓我們自定義返回體的頭部信息和狀態(tài)碼
當(dāng)我們將響應(yīng)體處理好了之后,調(diào)用response.end()
方法就可以將響應(yīng)體發(fā)送給客戶端 使用createServer
函數(shù)只是幫我們創(chuàng)建了一個(gè)Server
對(duì)象,并沒(méi)有讓其開(kāi)啟監(jiān)聽(tīng),我們還需要調(diào)用server
對(duì)象的listen
方法才可以進(jìn)行監(jiān)聽(tīng),真正作為一個(gè)服務(wù)器開(kāi)始運(yùn)行
listen
方法的第一個(gè)參數(shù)是監(jiān)聽(tīng)的端口號(hào),第二個(gè)參數(shù)則是綁定的主機(jī)ip
,第三個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),會(huì)被http
模塊異步調(diào)用,當(dāng)遇到錯(cuò)誤的時(shí)候,就能夠在這個(gè)回調(diào)函數(shù)的第一個(gè)參數(shù)中獲取到拋出的異常 ,我們可以選擇對(duì)異常進(jìn)行處理,讓我們的服務(wù)器更加健壯
下面是使用http
模塊創(chuàng)建一個(gè)簡(jiǎn)單服務(wù)器的例子
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
運(yùn)行它,創(chuàng)造一個(gè)屬于你的服務(wù)器!服務(wù)器運(yùn)行后,瀏覽器訪問(wèn)http://localhost:8080即可訪問(wèn)到這個(gè)服務(wù)器
也可以使用nodemon
運(yùn)行它,這樣當(dāng)我們的代碼發(fā)生變化的時(shí)候就不需要手動(dòng)終止程序再重新運(yùn)行了
npm i -g nodemon
建議全局安裝它,這樣就可以直接使用,不需要通過(guò)npx nodemon
去使用 使用也很簡(jiǎn)單,直接將node
命令改成nodemon
命令即可
nodemon http-server.js
3. 加上類型提示
前面我們?cè)谑褂?code>createServer以及resp
對(duì)象的時(shí)候,看不到任何的語(yǔ)法提示,必須隨時(shí)跟著node
官方文檔去邊用邊查,有點(diǎn)不方便 但是沒(méi)關(guān)系,我們可以使用ts
的.d.ts
文件幫助我們提供語(yǔ)法提示功能,注意,我們不是使用ts
進(jìn)行開(kāi)發(fā),只是使用它的語(yǔ)法提示功能而已
- 初始化項(xiàng)目 —
npm init -y
- 安裝
@types/node
—pnpm i @types/node -D
- 在項(xiàng)目目錄下創(chuàng)建
jsconfig.json
文件,將node_modules
排除在外,沒(méi)必要對(duì)其進(jìn)行檢查
{ "compilerOptions": { "checkJs": true }, "exclude": ["node_modules", "**/node_modules/*"] }
不知道你是否有發(fā)現(xiàn)上面的代碼其實(shí)是有一處錯(cuò)誤的呢?checkJs
能夠幫助我們檢查類型錯(cuò)誤問(wèn)題,可以根據(jù)需要選擇是否開(kāi)啟 可以看到,開(kāi)啟檢查后立馬就給我們提示了參數(shù)類型不匹配的問(wèn)題
這時(shí)候?qū)⑹髽?biāo)懸浮在listen
方法上,就能夠看到該方法的簽名
可以看到,原來(lái)port
參數(shù)需要是number
類型,但是我們定義的時(shí)候是string
類型,所以沒(méi)匹配上,將其修改為number
的8080
即可 而且可以直接查看到相關(guān)api
的文檔,不需要打開(kāi)node
官方的文檔找半天去查看了
4. 返回多個(gè)字符串的響應(yīng)體
前面我們的簡(jiǎn)單http server
中只返回了一句話,那么是否能夠返回多句話呢? 這就要用到resp
對(duì)象的write
方法了,end
只能夠返回一次內(nèi)容,而是用write
方法,我們可以多次寫(xiě)入內(nèi)容到響應(yīng)體中,最后只用調(diào)用一次end
,并且不傳遞任何參數(shù),只讓他完成發(fā)送響應(yīng)體的功能
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} ...`); });
這次我們寫(xiě)入了三句話,現(xiàn)在的效果就變成這樣啦
5. 返回html
我們不僅可以返回字符串給瀏覽器,還可以直接讀取html
文件的內(nèi)容并將其作為結(jié)果返回給瀏覽器 這就需要用到另一個(gè)Node.js
的內(nèi)置模塊 — fs
,該模塊提供了文件操作的功能 使用fs.readFile
可以異步進(jìn)行讀取文件的操作,但是它不會(huì)返回promise
對(duì)象,因此我們需要傳入回調(diào)去處理讀取到文件后的操作 還可以使用fs.readFileSync
進(jìn)行同步阻塞讀取文件,這里我們選擇異步讀取
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} ...`); });
現(xiàn)在的結(jié)果就像下面這樣:
成功將html
返回注意:這里需要將響應(yīng)頭的**Content-Type**
改為**text/html**
,告知瀏覽器我們返回的是**html**
文件的內(nèi)容,如果仍然以**text/plain**
返回的話,瀏覽器不會(huì)對(duì)返回的內(nèi)容進(jìn)行解析,即便它是符合**html**
語(yǔ)法的也不會(huì)解析,就像下面這樣:
6. 返回JSON
當(dāng)我們需要編寫(xiě)一個(gè)后端服務(wù)器,只負(fù)責(zé)返回接口數(shù)據(jù)的時(shí)候,就需要返回json
格式的內(nèi)容了,相信聰明的你也知道該怎么處理了:
- 將
MIME
類型設(shè)置為application/json
resp.write
的時(shí)候傳入的是json
字符串,可以使用JSON.stringify
處理對(duì)象后返回
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} ...`); });
結(jié)果如下:
7. 返回pdf文件
和之前返回html
文件的思路類似,都是一個(gè)設(shè)置響應(yīng)頭MIME
類型,讀取文件,返回文件內(nèi)容的過(guò)程 但是這次我們搞點(diǎn)不一樣的 我們的思路是在服務(wù)器運(yùn)行的時(shí)候生成一個(gè)pdf
文件,并將它返回 還需要將MIME
的類型改為application/pdf
生成pdf
文件需要用到一個(gè)庫(kù) — pdfkit
pnpm i pdfkit
首先我們編寫(xiě)一個(gè)創(chuàng)建pdf
文件的函數(shù),因?yàn)閯?chuàng)建pdf
文件還需要進(jìn)行一些寫(xiě)入操作,不確定什么時(shí)候會(huì)完成,但是我們的請(qǐng)求必須等到pdf
文件創(chuàng)建完成后才能得到響應(yīng) 所以我們需要將它變成異步進(jìn)行的,返回一個(gè)promise
/** * @description 創(chuàng)建 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
對(duì)象的內(nèi)容通過(guò)管道傳到新創(chuàng)建的寫(xiě)入流中,當(dāng)完成操作后我們就通過(guò)resovle
告知外界已經(jīng)創(chuàng)建好pdf
文件了 然后在服務(wù)端代碼中調(diào)用
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} ...`); });
現(xiàn)在瀏覽器就可以讀取到創(chuàng)建的pdf
文件了
8. 返回音頻文件
思路依然是一樣的,讀取一個(gè)音頻文件,然后通過(guò)管道將它送到resp
對(duì)象中再返回即可
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} ...`); });
效果如下
打開(kāi)后就是一個(gè)播放音頻的界面,這是chrome
提供的對(duì)音頻文件的展示,并且打開(kāi)控制臺(tái)會(huì)發(fā)現(xiàn)有返回音頻文件
注意:將音頻文件流通過(guò)管道傳到**resp**
后,不需要調(diào)用**resp.end()**
方法,因?yàn)檫@會(huì)關(guān)閉整個(gè)響應(yīng),導(dǎo)致音頻文件無(wú)法獲取
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} ...`); });
總結(jié)
我們學(xué)會(huì)了:
- 如何使用
Node
創(chuàng)建一個(gè)http
服務(wù)器 - 給
js
加上類型提示 - 如何返回字符串響應(yīng)體
- 如何返回
html
- 如何返回
JSON
- 如何生成并返回
pdf
文件 - 如何返回音頻文件
- 如何返回視頻文件
雖然內(nèi)容簡(jiǎn)單,但還是希望你能跟著動(dòng)手敲一敲,不要以為簡(jiǎn)單就看看就算了,看了不代表會(huì)了,真正動(dòng)手實(shí)現(xiàn)過(guò)后才會(huì)找到自己的問(wèn)題