Node.js 入门详解(一)
目錄
- 前言
- 1. 初識 Node.js
- 1.1 回顧與思考
- 1.2 Node.js 簡介
- 1.2.1 什么是Node.js
- 1.2.2 Node.js 中的 JavaScript 運行環境
- 1.2.3 Node.js 可以做什么
- 1.2.4 學習路徑
- 1.3 Node.js環境安裝
- 1.3.1 查看已安裝的Node.js版本號
- 1.3.2 什么是終端
- 1.4 Node.js 環境中執行 JavaScript 代碼
- 1.4.1 終端中的快捷鍵
- 2. fs 文件系統模塊
- 2.1 什么是fs文件系統模塊
- 2.2 讀取文件中的指定內容
- 2.2.1 fs.readFile() 的語法格式
- 2.2.2 示例代碼
- 2.2.3 判斷文件是否讀取成功
- 2.3 向指定的文件中寫入內容
- 2.3.1 fs.writeFile()語法格式
- 2.3.2 示例代碼
- 2.3.3 判斷文件是否寫入成功
- 2.4 stat 獲取文件信息
- 使用嚴格模式
- 2.5 練習-考試成績整理
- 2.5.1 核心實現步驟
- 2.5.2 考試成績整理練習答案(完整代碼)
- 2.5.3 附:JS常見轉義字符
- 2.6 fs 模塊 - 路徑動態拼接的問題
- :pushpin:小結
- 1 Node.js的交互模式和直接運行的區別
- 2 同步和異步的使用場景
- 3. path路徑模塊
- 3.1 path路徑模塊定義
- 3.2 路徑拼接
- 3.2.1 path.join的語法格式
- 3.2.2 代碼示例
- 3.3 獲取路徑中的文件名
- 3.3.1 path.basename() 的語法格式
- 3.3.2 代碼示例
- 3.4 獲取路徑中的文件擴展名
- 3.4.1 path.extname() 的語法格式
- 3.4.2 示例代碼
- 3.5 綜合案例-時鐘案例
- 3.5.1 案例要實現的功能
- 3.5.2 案例的實現步驟
- 步驟1 - 導入需要的模塊并創建正則表達式
- 步驟2 - 使用 fs 模塊讀取需要被處理的 html 文件
- 步驟3 – 自定義 resolveCSS 方法
- 步驟4 - 自定義resolveJS 方法
- 步驟5 – 自定義 resolveHTML 方法
- 3.5.4 案例的兩個注意點
- 4. http模塊
- 4.1 什么是http模塊
- 4.2 http 模塊的作用
- 4.3 服務器相關的概念
- 4.3.1 IP地址
- 4.3.2 域名和域名服務器
- 4.3.3 端口號
- 4.4 創建最基本的web服務器
- 4.4.1 . 創建 web 服務器的基本步驟
- 4.4.2 req 請求對象
- 4.4.3 res響應對象
- 4.4.4 解決中文亂碼問題
- 4.5 根據不同的 url 響應不同的 html 內容
- 4.5.1 核心實現步驟
- 4.5.2 動態響應內容
- 4.6 案例 - 實現 clock 時鐘的 web 服務器
- 4.6.1 核心思路
- 4.6.2 實現步驟
前言
學習 Node.js 需要具備的技術:
1. 初識 Node.js
1.1 回顧與思考
JavaScript 在瀏覽器中執行的原理
JavaScript 操作 DOM 和 BOM 原理
瀏覽器中的 JavaScript 運行環境
運行環境 是指 代碼正常運行所需的必要環境。
JavaScript 能否做后端開發?
除了Java、python、PHP做后端開發外,JavaScript 也可以做后端程序開發(需要Node.js 這個運行環境)
1.2 Node.js 簡介
1.2.1 什么是Node.js
Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環境。
在Node上運行的 JavaScript 相比其他后端開發語言有何優勢?
最大的優勢是借助 JavaScript 天生的事件驅動機制加 V8 高性能引擎,使編寫高性能Web服務輕而易舉。
其次,JavaScript 語言本身是完善的函數式語言,在前端開發時,開發人員往往寫得比較隨意,讓人感覺 JavaScript就是個“玩具語言”。但是,在Node環境下,通過模塊化的 JavaScript 代碼,加上函數式編程,并且無需考慮瀏覽器兼容性問題,直接使用最新的ECMAScript 6標準,可以完全滿足工程上的需求。
Node.js 官網地址: https://nodejs.org/zh-cn/
相關技術/論述:https://www.liaoxuefeng.com/wiki/1022910821149312/1023025235359040
1.2.2 Node.js 中的 JavaScript 運行環境
- 注意:
- 瀏覽器 是JavaScript 的 前端運行環境。
- Node.js 是 JavaScript 的 后端運行環境。
- Node.js 中 無法調用 DOM 和 BOM 等瀏覽器內置 API。
1.2.3 Node.js 可以做什么
Node.js 作為一個 JavaScript 的運行環境,僅僅提供了基礎的功能和 API。然而,基于 Node.js 提供的這些基礎能,很多強大的工具和框架如雨后春筍,層出不窮,所以學會了 Node.js ,可以讓前端程序員勝任更多的工作和崗位:
etc…
總之:Node.js 是 大前端時代 的“大寶劍”,有了 Node.js 這個超級 buff 的加持,前端程序員的 行業競爭力 會越來越強!
1.2.4 學習路徑
瀏覽器中的 JavaScript 學習路徑:
JavaScript 基礎語法 + 瀏覽器內置 API(DOM + BOM) + 第三方庫(jQuery、art-template 等)
Node.js 的學習路徑:
JavaScript 基礎語法 + Node.js 內置 API 模塊(fs、path、http等)+ 第三方 API 模塊(express、mysql 等)
1.3 Node.js環境安裝
由于 Node.js 平臺是在后端運行 JavaScript 代碼,所以,必須必須首先在計算機上安裝 Node.js 環境。
安裝包可以從 Node.js 的官網首頁直接下載,進入到 Node.js 的官網首頁(https://nodejs.org/en/),點擊綠色的按鈕,下載所需的版本后(建議穩定版)。
【安裝】:雙擊直接安裝,不建議更改默認安裝位置(C:\),中途也保持默認設置,一路 “Next” 即可。
LTS :長期穩定版 — 對于追求穩定性的企業級項目來說,推薦安裝 LTS 版本的 Node.js。
Current :新特性嘗鮮版 — 對熱衷于嘗試新特性的用戶來說,推薦安裝 Current 版本的 Node.js。但是,Current 版本中可能存在隱藏的 Bug 或安全性漏洞,因此不推薦在企業級項目中使用 Current 版本的 Node.js。
1.3.1 查看已安裝的Node.js版本號
Windows系統,打開 cmd 命令行終端,輸入命令 node –v,按下回車鍵,即可查看已安裝的 Node.js 的版本號(能看到版本號,則代表 Node.js 安裝成功)。
注意命令行模式和交互模式,看到類似C:\>是在Windows提供的命令行模式:
看到 > 是在Node交互式環境下:
1、命令提示符后輸入node,就會進入 Node.js 的交互環境。在交互環境下,你可以輸入任意 JavaScript 語句,例如100+200,回車后將得到輸出結果。
2、要退出 Node.js 環境,連按兩次Ctrl+C。
此外,在命令行模式運行.js文件和在Node交互式環境下直接運行 JavaScript 代碼有所不同。Node交互式環境會把每一行JavaScript代碼的結果自動打印出來(直接看到結果),但是,直接運行JavaScript文件則不會。
快速打開 cmd 終端的方式:
使用快捷鍵( Windows徽標鍵 + R)打開運行面板,輸入 cmd 后直接回車,即可打開終端。
除了 cmd 終端外,還可以使用 Powershell終端。快速打開方式為,在當前文件所在目錄下,shift + 右鍵,在彈出的菜單中,選擇Powershell,如圖所示:
1.3.2 什么是終端
終端(英文:Terminal)是專門為開發人員設計的,用于實現人機交互 的一種方式。
作為一名合格的程序員,我們有必要識記一些 常用的終端命令,來輔助我們更好的操作與使用計算機
1.4 Node.js 環境中執行 JavaScript 代碼
語法格式:node 要執行的js文件的路徑
1.4.1 終端中的快捷鍵
在 Windows 的 powershell 或 cmd 終端中,我們可以通過如下快捷鍵,來提高終端的操作效率:
使用 ↑ 鍵,可以快速定位到上一次執行的命令;
使用 tab鍵,能夠快速補全路徑;
使用 ESC 鍵,能夠快速清空當前已輸入的命令;
輸入 cls 命令,可以清空終端;
2. fs 文件系統模塊
2.1 什么是fs文件系統模塊
fs 模塊是 Node.js 官方提供的、用來讀、寫文件的模塊。它提供了一系列的方法和屬性,用來滿足用戶對文件的操作需求。
因為 Node.js 是運行在服務端的 JavaScript 環境,服務器程序和瀏覽器程序相比,最大的特點是沒有瀏覽器的安全限制了,而且,服務器程序必須能接收網絡請求,讀寫文件,處理二進制內容,所以,Node.js 內置的常用模塊就是為了實現基本的服務器功能。這些模塊在瀏覽器環境中是無法被執行的,因為它們的底層代碼是用 C/C++ 在 Node.js 運行環境中實現的。
我們知道,JavaScript 有且僅有一個全局對象,在瀏覽器中叫window對象。而在Node.js環境中,也有唯一的全局對象,不過它不叫window了,而是叫global。
和所有其它 JavaScript 模塊不同的是,fs 模塊同時提供了 異步 和 同步 的方法。
回顧一下什么是異步方法。因為 JavaScript 的單線程模型,執行IO操作時,JavaScript 代碼無需等待,而是傳入回調函數后,繼續執行后續JavaScript代碼。比如 jQuery 提供的 getJSON() 操作;而同步的IO操作則需要等待函數返回
例如:
fs.readFile() 方法:用來 讀取 指定文件中的內容
fs.writeFile()方法:用來向指定的文件中 寫入內容
如果要在 JavaScript 代碼中,使用 fs 模塊來操作文件,則需要使用如下的方式先導入它:
// 導入 fs const fs = require ('fs')附:如何判斷JavaScript執行環境
有很多 JavaScript 代碼既能在瀏覽器中執行,也能在 Node 環境執行,但有些時候,程序本身需要判斷自己到底是在什么環境下執行的,常用的方式就是根據瀏覽器和 Node 環境提供的全局變量名稱來判斷:
if (typeof(window) === 'undefined') {
console.log('node.js');
} else {
console.log('browser');
}
2.2 讀取文件中的指定內容
2.2.1 fs.readFile() 的語法格式
使用 fs.readFile() 方法,可以 讀取 指定文件中的內容,語法格式如下:
fs.readFile(path[, options],callback)- 參數解釋:
- 參數1:必選 參數,字符串,表示文件的路徑。
- 參數2:可選參數,表示以什么 編碼格式 來讀取文件。
- 參數3:必選 參數,文件讀取完成后,通過回調函數拿到讀取的結果。
2.2.2 示例代碼
以 utf8 的編碼格式,讀取指定文件的內容,并打印 err 和 dataStr 的值:
const fs = require ('fs') fs.readFile('./files/123.txt','utf8',function(err,dataStr){console.log(err);console.log('-----');console.log(dataStr); })2.2.3 判斷文件是否讀取成功
異步讀取時,傳入的回調函數接收兩個參數,當正常讀取時,err參數為null,data參數為讀取到的String。當讀取發生錯誤時,err參數代表一個錯誤對象,data為undefined。這也是Node.js標準的回調函數:第一個參數代表錯誤信息,第二個參數代表結果。后面我們還會經常編寫這種回調函數。
由于err是否為null就是判斷是否出錯的標志,所以通常的判斷邏輯總是:
if (err) {// 出錯了 } else {// 正常 }例如,獲取文件讀取的結果可寫成如下代碼:
const fs = require ('fs') fs.readFile('./files/123.txt','utf8',function(err,dataStr){if(err){return console.log('文件讀取失敗'+ err.message);}console.log('文件讀取成功,內容是:'+ result ); })如果我們要讀取的文件不是文本文件,而是二進制文件,怎么辦?
下面的例子演示了如何讀取一個圖片文件:
'use strict';var fs = require('fs');fs.readFile('sample.png', function (err, data) {if (err) {console.log(err);} else {console.log(data);console.log(data.length + ' bytes');} });當讀取二進制文件時,不傳入文件編碼時,回調函數的data參數將返回一個Buffer對象。在Node.js中,Buffer對象就是一個包含零個或任意個字節的數組(注意和Array不同)。
Buffer對象可以和String作轉換,例如,把一個Buffer對象轉換成String:
// Buffer -> String var text = data.toString('utf-8'); console.log(text);或者把一個String轉換成Buffer:
// String -> Buffer var buf = Buffer.from(text, 'utf-8'); console.log(buf);2.3 向指定的文件中寫入內容
2.3.1 fs.writeFile()語法格式
使用fs.writeFile()方法,可以向指定的文件中寫入內容,語法格式如下:
fs.writeFile(file,data[,options],callback)writeFile()的參數依次為文件、數據和回調函數。如果傳入的數據是String,默認按UTF-8編碼寫入文本文件,如果傳入的參數是Buffer,則寫入的是二進制文件。回調函數由于只關心成功與否,因此只需要一個err參數。
- 參數解釋:
- 參數1:必選參數,需要指定一個文件路徑的字符串,表示文件的存放路徑。
- 參數2:必選參數,表示要寫入的內容。
- 參數3:可選參數,表示以什么格式寫入文件內容,默認值是 utf8。
- 參數4:必選參數,文件寫入完成后的回調函數。
2.3.2 示例代碼
向指定的文件路徑中,寫入文件內容
const fs = require('fs') fs.writeFile('./files/123.txt','Hello Node.js!',function(err){console.log(err); // 輸出結果為 null })注: 如果 files 文件夾下不存在 123.txt 文件,則會自動創建該文件,并寫入 Hello Node.js! 這個內容
2.3.3 判斷文件是否寫入成功
通過判斷 err 對象是否為 null,獲取文件寫入的結果:
const fs = require('fs') fs.writeFile('./files/123.txt','Hello Node.js!',function(err){if(err){return console.log('文件寫入失敗!'+ err.message);};console.log('文件寫入成功!'); })2.4 stat 獲取文件信息
如果我們要獲取文件大小,創建時間等信息,可以使用fs.stat(),它返回一個Stat對象,能告訴我們文件或目錄的詳細信息:
'use strict';var fs = require('fs');fs.stat('sample.txt', function (err, stat) {if (err) {console.log(err);} else {// 是否是文件:console.log('isFile: ' + stat.isFile());// 是否是目錄:console.log('isDirectory: ' + stat.isDirectory());if (stat.isFile()) {// 文件大小:console.log('size: ' + stat.size);// 創建時間, Date對象:console.log('birth time: ' + stat.birthtime);// 修改時間, Date對象:console.log('modified time: ' + stat.mtime);}} });fs.stat() 運行結果如下:
isFile: true isDirectory: false size: 145 birth time: Fri Dec 09 2020 09:43:41 GMT+0800 (CST) modified time: Fri Dec 09 2020 12:09:00 GMT+0800 (CST)使用嚴格模式
如果在 JavaScript 文件開頭寫上'use strict';,那么 Node 在執行該 JavaScript 時將使用嚴格模式。但是,在服務器環境下,如果有很多 JavaScript 文件,每個文件都寫上 'use strict';很麻煩。我們可以給Nodejs傳遞一個參數,讓Node直接為所有js文件開啟嚴格模式:
// 給 Node傳遞 --use_strict 參數來開啟嚴格模式 node --use_strict calc.js2.5 練習-考試成績整理
案例中需要用到的素材:網盤下載
使用 fs 文件系統模塊,將素材目錄下的《成績.txt》文件中的考試數據,整理到《成績-ok.txt》文件中。
整理前,成績.txt文件中的數據格式如下:
整理完成之后,希望得到的《成績-OK.txt》文件中的數據格式如下:
2.5.1 核心實現步驟
2.5.2 考試成績整理練習答案(完整代碼)
// 1. 導入 fs 模塊 const fs = require('fs')// 2. 調用 fs.readFile() 讀取文件的內容 fs.readFile('../素材/成績.txt', 'utf8', function(err, dataStr) {// 3. 判斷是否讀取成功if (err) {return console.log('讀取文件失敗!' + err.message)}// console.log('讀取文件成功!' + dataStr)// 4.1 先把成績的數據,按照空格進行分割const arrOld = dataStr.split(' ')// 4.2 循環分割后的數組,對每一項數據,進行字符串的替換操作const arrNew = []arrOld.forEach(item => {arrNew.push(item.replace('=', ':'))})// 4.3 把新數組中的每一項,進行合并,得到一個新的字符串const newStr = arrNew.join('\r\n')// 5. 調用 fs.writeFile() 方法,把處理完畢的成績,寫入到新文件中fs.writeFile('./files/成績-ok.txt', newStr, function(err) {if (err) {return console.log('寫入文件失敗!' + err.message)}console.log('成績寫入成功!')}) })【代碼解釋】
arrNew.join('\r\n'):\r\n 在windows 里表示回車換行。
\r(回車),英文是Carriage return,表示使光標下移一格
\n(換行),英文是New line,表示使光標到行首
📌小貼士:
日常開發中,有時候后臺傳來的字符串數據中是有回車符的,我們想要的效果是有回車符則自動換行。如果發現替換\n無效果,可以試著換成\r或者\r\n再看結果,總有一種可以替換成功。
示例:
2.5.3 附:JS常見轉義字符
| \b | 退格(BS 或 ASCII 符號 0x08 (8)) |
| \f | 換頁(FF 或 ASCII 符號 0x0C (12)) |
| \n | 換行(LF 或 ASCII 符號 0x0A (10)) |
| \r | 回車(CR 或 ASCII 符號 0x0D (13)) |
| \t | 水平制表符(HT 或 ASCII 符號 0x09 (9)) |
| \' | 單引號 |
| \" | 雙引號 |
| \& | &(and)符號 |
擴展:換行(\n)和回車(\r)的區別
這個東西的說法來自打字機,以前的打字機要新起一行的時候有兩步:
1、打字的機頭回到開始位置,這是回車;
2、紙張往上推進一行,這是換行。
現在電腦上的 回車換行 其實已經是個整體的概念了
2.6 fs 模塊 - 路徑動態拼接的問題
問題: 在使用 fs 模塊操作文件時,如果提供的操作路徑是以 ./ 或 …/ 開頭的相對路徑時,很容易出現路徑動態拼接錯誤的問題。
原因: 代碼在運行的時候,會以執行 node 命令時所處的目錄,動態拼接出被操作文件的完整路徑。
解決方案: 在使用 fs 模塊操作文件時,直接提供完整的路徑,不要提供 ./ 或 …/ 開頭的相對路徑,從而防止路徑動態拼接的問題。
// 不要使用./ 或 ../ 這樣的相對路徑 fs.readFile('./files/123.txt','utf8',function(err,dataStr){if (err) return console.log('讀取文件失敗!' + err.message);console.log(dataStr); })// __dirname 表示當前文件所處的目錄 fs.readFile(__dirname + '/files/1.txt','utf8',function(err,dataStr){if(err) return console.log('讀取文件失敗!' + err.message);console.log(dataStr); })注:類似 D:\ node \ FW 這樣的路徑,需要更改為 D: \ \ node \ \ FW 這樣的雙斜線。因為在 js 里單 \ 代表轉義,斜線后的字符才是真正需要的字符。
📌小結
1 Node.js的交互模式和直接運行的區別
用文本編輯器寫 JavaScript 程序,然后保存為后綴為 .js 的文件,就可以用 node 直接運行這個程序了。
Node 的交互模式和直接運行.js文件有什么區別呢?
直接輸入node進入交互模式,相當于啟動了Node解釋器,但是等待你一行一行地輸入源代碼,每輸入一行就執行一行。
直接運行xxx.js文件相當于啟動了Node解釋器,然后一次性把xxx.js文件的源代碼給執行了,你是沒有機會以交互的方式輸入源代碼的。
🔔 小貼士:
在編寫JavaScript代碼的時候,完全可以一邊在文本編輯器里寫代碼,一邊開一個Node交互式命令窗口,在寫代碼的過程中,把部分代碼粘到命令行去驗證,事半功倍!前提是得有個27’的超大顯示器!😃
2 同步和異步的使用場景
在 fs 模塊中,提供同步方法是為了方便使用。那我們到底是應該用異步方法還是同步方法呢?
由于 Node.js 環境執行的 JavaScript 代碼是服務器端代碼,所以,絕大部分需要在服務器運行期反復執行業務邏輯的代碼,必須使用異步代碼,否則,同步代碼在執行時期,服務器將停止響應,因為 JavaScript 只有一個執行線程。
服務器啟動時如果需要讀取配置文件,或者結束時需要寫入到狀態文件時,可以使用同步代碼,因為這些代碼只在啟動和結束時執行一次,不影響服務器正常運行時的異步執行。
3. path路徑模塊
3.1 path路徑模塊定義
path 模塊是 Node.js 官方提供的、用來處理路徑的模塊。它提供了一系列的方法和屬性,用來滿足用戶對路徑的處理需求。
例如:
-
path.join() 方法:用來將多個路徑片段拼接成一個完整的路徑字符串;
-
path.basename() 方法:用來從路徑字符串中,將文件名解析出來
如果要在 JavaScript 代碼中,使用 path 模塊來處理路徑,則需要使用如下的方式先導入它:
// 導入 path 模塊 const path = require('path')3.2 路徑拼接
3.2.1 path.join的語法格式
使用 path.join() 方法,可以把多個路徑片段拼接為完整的路徑字符串,語法格式如下:
path.join(...paths)【參數解釋】
- …paths :< string> 路徑片段的序列;
- 返回值:< string>
3.2.2 代碼示例
使用 path.join() 方法,可以把多個路徑片段拼接為完整的路徑字符串:
🔔 注: 凡是涉及到路徑拼接的操作,都要使用 path.join() 方法進行處理。不要直接使用 + 進行字符串的拼接。
上面示例代碼中的路徑字符串 ../ ,會抵銷掉一層路徑,因此最終輸出的路徑中,不包含路徑片斷c 。
3.3 獲取路徑中的文件名
3.3.1 path.basename() 的語法格式
使用 path.basename() 方法,可以獲取路徑中的最后一部分,經常通過這個方法獲取路徑中的文件名,語法格式如下:
【參數解釋】
path < string> 必選參數,表示一個路徑的字符串
ext < string> 可選參數,表示文件擴展名
返回:< string> 表示路徑中的最后一部分
3.3.2 代碼示例
使用 path.basename() 方法,可以從一個文件路徑中,獲取到文件的名稱部分:
const fpath='/a/b/c/index.html' //文件的存放路徑var fullName=path.basename(fpath) console.log(fullName); // 輸出index.htmlvar nameWithoutExt=path.basename(fpath,'.html') console.log(nameWithoutExt); // 輸出index3.4 獲取路徑中的文件擴展名
3.4.1 path.extname() 的語法格式
使用 path.extname() 方法,可以獲取路徑中的擴展名部分,語法格式如下:
【參數解釋】
- path 必選參數,表示一個路徑的字符串;
- 返回: 返回得到的擴展名字符串。
3.4.2 示例代碼
使用 path.extname() 方法,可以獲取路徑中的擴展名部分:
const fpath='/a/b/c/index.html' //路徑字符串const fext=path.extname(fpath) console.log(fext); // 輸出 .html3.5 綜合案例-時鐘案例
3.5.1 案例要實現的功能
將素材目錄下的 index.html 頁面,拆分成三個文件,分別是:
- index.css
- index.js
- index.html
并且將拆分出來的 3 個文件,存放到 clock 目錄中。
3.5.2 案例的實現步驟
- 創建兩個正則表達式,分別用來匹配 <style> 和 <script> 標簽;
- 使用 fs 模塊,讀取需要被處理的 HTML文件;
- 自定義 resolveCSS 方法,來寫入 index.css 樣式文件;
- 自定義 resolveJS 方法,來寫入index.js 腳本文件;
- 自定義 resolveHTML 方法,來寫入 index.html 文件。
步驟1 - 導入需要的模塊并創建正則表達式
// 1、導入fs 文件系統模塊 const fs=require('fs'); // 2、導入 path 路徑處理模塊 const path = require('path')// 3、匹配<style></style> 標簽的正則 // 其中 \s 表示空白字符;\S 表示非空白字符;* 表示匹配任意次 const regStyle=/<style>[\s\S]*<\/style>/// 4、匹配<script></script> 標簽的正則 const regScript=/<script>[\s\S]*<\/script>/步驟2 - 使用 fs 模塊讀取需要被處理的 html 文件
// 1、讀取需要被處理的 HTML 文件 fs.readFile(path.join(__dirname,'../素材/index.html'),'utf8',(err,dataStr)=>{// 2、讀取 HTML 文件失敗if (err) return console.log('讀取HTML文件失敗!' + err.message);// 3、讀取 HTML 文件成功后,調用對應的方法,拆解出 css、js 和 html 文件resolveCSS(dataStr);resolveJS(dataStr);resolveHTML(dataStr); })步驟3 – 自定義 resolveCSS 方法
// 處理 css 樣式 function resolveCSS(htmlStr){// 1、使用正則提取頁面中的 <style></style> 標簽const r1=regStyle.exec(htmlStr);// 2、將提取出來的樣式字符串,做進一步的處理const newCSS=r1[0].replace('<style>','').replace('</style>','');// 3、將提取出來的 css 樣式,寫入到 index.css 文件中fs.writeFile(path.join(__dirname,'./clock/index.css'),newCSS,err =>{if(err) return console.log('寫入 css 樣式失敗!'+ err.message);console.log('寫入 CSS 樣式成功!');}) }exec() 方法用于檢索字符串中的正則表達式的匹配。
返回一個數組,其中存放匹配的結果。如果未找到匹配,則返回值為 null。此數組的第 0 個元素就是與正則表達式相匹配的文本
==> exec()的更多詳情,請參閱 w3school文檔
步驟4 - 自定義resolveJS 方法
// 處理 JS 腳本 function resolveJS(htmlStr){// 1、使用正則提取頁面中的 <script></script> 標簽const r2=regScript.exec(htmlStr);// 2、將提取出來的腳本字符串,做進一步的處理const newJS=r2[0].replace('<script>','').replace('</script>','');// 3、將提取出來的 js 腳本,寫入到 index.js 文件中fs.writeFile(path.join(__dirname,'./clock/index.js'),newJS,err =>{if(err) return console.log('寫入 JavaScript 腳本失敗!'+ err.message);console.log('寫入 JS 腳本成功!');}) }步驟5 – 自定義 resolveHTML 方法
// 處理 HTML 文件 function resolveHTML(htmlStr){ // 1、使用字符串的replace 方法,把內嵌的 <style> 和 <script> 標簽,替換為外聯的<link> 和 <script>標簽 const newHTML=htmlStr.replace(regStyle,'<link rel="stylesheet" href="./index.css" />').replace(regStyle,'<script src="./index.js"></script>')// 2、將替換完成之后的 html 代碼,寫入到 indexedDB.html 文件中fs.writeFile(path.join(__dirname,'./clock/index.html'),newHTML,err =>{if (err) return console.log('寫入 HTML 文件失敗!' + err.message);console.log('寫入 HTML 頁面成功!');}) }3.5.4 案例的兩個注意點
📌 注意:
4. http模塊
4.1 什么是http模塊
回顧:什么是客戶端、什么是服務器?
在網絡節點中,負責消費資源的電腦,叫做客戶端;負責對外提供網絡資源的電腦,叫做服務器。
http 模塊是 Node.js 官方提供的、用來創建 web 服務器的模塊。通過 http 模塊提供的 http.createServer() 方法,就能方便的把一臺普通的電腦,變成一臺 Web 服務器,從而對外提供 Web 資源服務。
如果要希望使用 http 模塊創建 Web 服務器,則需要先導入它:
// 導入 http 模塊 const http = require('http')4.2 http 模塊的作用
服務器和普通電腦的區別在于,服務器上安裝了 web 服務器軟件,例如:IIS、Apache 等。通過安裝這些服務器軟件,就能把一臺普通的電腦變成一臺 web 服務器。
在 Node.js 中,我們不需要使用 IIS、Apache 等這些第三方 web 服務器軟件。因為我們可以基于 Node.js 提供的 http 模塊,通過幾行簡單的代碼,就能輕松的手寫一個服務器軟件,從而對外提供 web 服務。
4.3 服務器相關的概念
4.3.1 IP地址
IP 地址就是互聯網上每臺計算機的唯一地址,因此 IP 地址具有唯一性。如果把“個人電腦”比作“一臺電話”,那么“IP地址”就相當于“電話號碼”,只有在知道對方 IP 地址的前提下,才能與對應的電腦之間進行數據通信。
IP 地址的格式:通常用“點分十進制”表示成(a.b.c.d)的形式,其中,a,b,c,d 都是 0~255 之間的十進制整數。例如:用點分十進表示的 IP地址(192.168.1.1)
🚥 注意:
互聯網中每臺 Web 服務器,都有自己的 IP 地址,例如:大家可以在 Windows 的終端中運行 ping www.baidu.com 命令,即可查看到百度服務器的 IP 地址。
在開發期間,自己的電腦既是一臺服務器,也是一個客戶端,為了方便測試,可以在自己的瀏覽器中輸入 127.0.0.1 這個 IP 地址,就能把自己的電腦當做一臺服務器進行訪問了。
4.3.2 域名和域名服務器
盡管 IP 地址能夠唯一地標記網絡上的計算機,但IP地址是一長串數字,不直觀,而且不便于記憶,于是人們又發明了另一套字符型的地址方案,即所謂的域名(Domain Name)地址。
IP地址和域名是一一對應的關系,這份對應關系存放在一種叫做域名服務器(DNS,Domain name server)的電腦中。使用者只需通過好記的域名訪問對應的服務器即可,對應的轉換工作由域名服務器實現。因此,域名服務器就是提供 IP 地址和域名之間的轉換服務的服務器。
🔔 注意:
單純使用 IP 地址,互聯網中的電腦也能夠正常工作。但是有了域名的加持,能讓互聯網的世界變得更加方便。
在開發測試期間, 127.0.0.1 對應的域名是 localhost,它們都代表我們自己的這臺電腦,在使用效果上沒有任何區別。
4.3.3 端口號
計算機中的端口號,就如同現實生活中的門牌號。通過門牌號,外賣小哥可以在整棟大樓眾多的房間中,準確把外賣送到你的手中。
同樣的道理,在一臺電腦中,可以運行成百上千個 web 服務。每個 web 服務都對應一個唯一的端口號。客戶端發送過來的網絡請求,通過端口號,可以被準確地交給 對應的 web 服務 進行處理。
?? 注意:
每個端口號不能同時被多個 web 服務占用。
在實際應用中,URL 中的 80 端口可以被省略。
4.4 創建最基本的web服務器
4.4.1 . 創建 web 服務器的基本步驟
1)步驟1 - 導入http 模塊
如果希望在自己的電腦上創建一個 web 服務器,對外提供 web 服務,則需要導入 http 模塊:
// 導入 http 模塊 const http = require('http')2)步驟2 - 創建 web 服務器實例
調用 http.createServer() 方法,即可快速創建一個 web 服務器實例:
const server = http.createServer()3) 步驟3 - 為服務器實例綁定 request 事件
為服務器實例綁定 request 事件,即可監聽客戶端發送過來的網絡請求:
// 使用服務器實例的 .on( ) 方法,為服務器綁定一個request 事件 server.on('request',function(req,res){// 只要有客戶端向我們自己的服務器發起請求,就會觸發request 事件,//從而調用 這個事件處理函數console.log('someone visit our web server.') })4)步驟4 - 啟動服務器
調用服務器實例的 .listen() 方法,即可啟動當前的 web 服務器實例:
// 調用 server.listen(端口號,cb回調)方法,即可啟動 web 服務器 server.listen(80,function(){console.log('http server running at http://127.0.0.1') })按下 Ctrl + c 停止服務器
4.4.2 req 請求對象
只要服務器接收到了客戶端的請求,就會調用通過 server.on( ) 為服務器綁定的 request 事件處理函數。
如果想在事件處理函數中,訪問與客戶端相關的數據或屬性,可以使用如下的方式:
server.on('request',function(req){// req是請求對象,它包含了與客戶端相關的數據和屬性,例如:// req.url 是客戶端請求的 URL地址;// req.method 是客戶端的 method 請求類型const str = `Your request url is ${req.url},and request method is ${req.method}`console.log(str) })4.4.3 res響應對象
在服務器的 request 事件處理函數中,如果想訪問與服務器相關的數據或屬性,可以使用如下的方式:
server.on('request',function(req,res){// res 是響應對象,它包含了與服務器相關的數據和屬性,如:// 要發送到客戶端的字符串const str = `Your request url is ${req.url},and request method is ${req.method}`// res.end() 方法的作用:// 向客戶端發送指定的內容,并結束這次請求的處理過程res.end(str) })4.4.4 解決中文亂碼問題
當調用 res.end() 方法,向客戶端發送中文內容的時候,會出現亂碼問題,此時,需要手動設置內容的編碼格式:
server.on('request',function(req,res){// 發送的內容包含中文const str = `您請求的 url 地址是 ${req.url},請求的 method 類型是 ${req.method}`// 為了防止中文顯示亂碼的問題,需要設置響應頭 Content-Type 的// 值為 text/html:charset=utf-8res.setHeader('Content-Type','text/html;charset=utf-8')// 把包含中文的內容,響應給客戶端res.end(str) })Content-Type:告訴瀏覽器以什么樣的編碼格式來解析響應回去的內容。
4.5 根據不同的 url 響應不同的 html 內容
4.5.1 核心實現步驟
4.5.2 動態響應內容
// 導入http模塊 const http = require('http') // 創建web服務器實例 const server = http.createServer()server.on('request', (req, res) => {// 1、獲取請求的 url 地址const url = req.url// 2、設置默認的響應內容為 404 Not foundlet content = '<h1>404 Not found</h1>'// 3、判斷用戶請求的是否為 / 或 /indexe.html 首頁// 4、判斷用戶請求的是否為 /about.html 關于頁面if (url === '/' || url === '/index.html') {content = '<h1>首頁</h1>'} else if (url === '/about.html') {content = '<h1>關于頁面</h1>'}// 5、設置 Content-Type 響應頭,防止中文亂碼res.setHeader('Content-Type', 'text/html; charset=utf-8')// 6、使用 res.end() 把內容響應回客戶端res.end(content) })server.listen(80, () => {console.log('server running at http://127.0.0.1'); })4.6 案例 - 實現 clock 時鐘的 web 服務器
4.6.1 核心思路
把文件的 實際存放路徑,作為 每個資源的 請求 url 地址。
4.6.2 實現步驟
1)步驟1 - 導入需要的模塊
// 1.1 導入需要的http 模塊 const http = require('http') // 1.2、導入 fs 文件系統模塊 const fs = require('fs') // 1.3、導入Path 路徑處理模塊 const path = require('path')2)步驟2 - 創建基本的 web 服務器
// 2.1 創建 web 服務器 const server = http.createServer(); // 2.2 監聽 web 服務器的 request 事件 server.on('request', (req, res) => {}); // 2.3 啟動服務器 server.listen(80, () => {console.log('server running at http://127.0.0.1'); });3)步驟3 - 將資源的請求 url 地址映射為文件的存放路徑
// 3.1 獲取到客戶端請求的 URL 地址 const url = req.url // 3.2 把請求的 URL 地址映射為具體文件的存放路徑 const fpath=path.join(__dirname,url)4)步驟4 - 讀取文件的內容并響應給客戶端
// 4.1 根據“映射”過來的文件路徑讀取文件的內容 fs.readFile(fpath, 'utf8', (err, dataStr) => {// 4.2 讀取失敗,向客戶端響應固定的“錯誤信息”if (err) return res.end('<h1>404 Not found</h1>');// 4.3 讀取成功,將讀取成功的內容,響應給客戶端res.end(dataStr); })5)步驟5 - 優化資源的請求路徑
// *** 將 3.2 的實現方式,改為如下代碼 *** // 5.1 預定義空白的文件存放路徑 let fpath = '' if (url==='/') {// 5.2 如果請求的路徑為 /,則手動指定文件的存放路徑fpath = path.join(__dirname,'./clock/index.html') } else {// 5.3 如果請求的路徑不為/,則動態拼接文件的存放路徑fpath = path.join(__dirname,'./clock',url) }<<< 第一部分(完)
下一篇:Node.js 入門詳解(二)
總結
以上是生活随笔為你收集整理的Node.js 入门详解(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 支付宝和微信的JSSDK发起支付
- 下一篇: 二维数组使用