柚子快報(bào)激活碼778899分享:vim node.js學(xué)習(xí)
柚子快報(bào)激活碼778899分享:vim node.js學(xué)習(xí)
node.js學(xué)習(xí)實(shí)操及筆記
溫故node.js,node.js學(xué)習(xí)實(shí)操過程及筆記~
node.js學(xué)習(xí)視頻node.js官網(wǎng)node.js中文網(wǎng)實(shí)操筆記githubcsdn筆記
為什么學(xué)node.js
可以讓別人訪問我們編寫的網(wǎng)頁為后續(xù)的框架學(xué)習(xí)打下基礎(chǔ),三大框架vue react angular離不開node.js
node.js是什么
官網(wǎng):node.js是一個(gè)開源的、跨平臺(tái)的運(yùn)行JavaScript的運(yùn)行環(huán)境。通俗理解: 一款應(yīng)用程序,一款軟件,可以運(yùn)行JavaScript
node.js作用
開發(fā)服務(wù)器應(yīng)用開發(fā)工具類應(yīng)用開發(fā)桌面類應(yīng)用
node.js安裝
node.js官網(wǎng)node.js中文網(wǎng)全部版本安裝包淘寶鏡像
點(diǎn)擊安裝,傻瓜式安裝。
PS:推薦使用nvm方式安裝node.js,這樣可實(shí)現(xiàn)自由切換版本好。
因?yàn)橛械睦享?xiàng)目node.js可能是12版本的,新項(xiàng)目又是18或者20版本。具體安裝自行查閱,目前這邊已經(jīng)安裝,忘記哪個(gè)博主寫的較好就不推薦了。
檢測(cè)安裝是否成功,輸入以下命令到命令行,出來版本號(hào)代表安裝成功
node -v
若安裝失敗,考慮大可能為環(huán)境變量配置問題影響
node.js初體驗(yàn)
當(dāng)前目錄新建hello.js
console.log("hello node.js!");
切換到當(dāng)前目錄,終端打開執(zhí)行代碼,看到 hello node.js 注意:運(yùn)行命令為node + 文件路徑 =》hello.js是相對(duì)文件路徑,這里省略了./hello.js
node hello.js
node.js注意事項(xiàng)
node.js不能使用BOM、DOM的API,可以使用console和定時(shí)器APInode.js中頂級(jí)對(duì)象為global,也可以用globalThis訪問頂級(jí)對(duì)象
// BOM不可用
console.log(window);
console.log(history);
console.log(navigator);
console.log(location)
//DOM不可用
console.log(document);
//global可用 globalthis可用
console.log(global)
//定時(shí)器可用
setTimeout(()=>{
console.log('hello~')
})
Buffer緩沖器
Buffer概念
概念
Buffer是一個(gè)類似數(shù)組的對(duì)象,用于固定長(zhǎng)度的字節(jié)序列Buffer本質(zhì)是一段內(nèi)存空間,專門用來處理二進(jìn)制數(shù)據(jù)
特點(diǎn)
Buffer大小固定且無法調(diào)整Buffer性能較好,可以直接對(duì)計(jì)算機(jī)內(nèi)存進(jìn)行操作每個(gè)元素的大小為1字節(jié) 3.創(chuàng)建BufferallocallocUnsafefrom
node.js內(nèi)置模塊Buffer,不需引入,理解為全局變量
//1.alloc
let buf = Buffer.alloc(10);
console.log(buf);
console.log('-------')
// 2.allocUnsafe;
let buf_2 = Buffer.allocUnsafe(10000);
console.log(buf_2);
console.log('-------')
//3.from
//打印出ASCII碼字符代碼表的值
let buf_3 = Buffer.from('hello');
console.log(buf_3);
console.log('-------');
//打印出二進(jìn)制的值
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
console.log(buf_4);
console.log('-------');
Buffer操作以及注意點(diǎn)
字符串轉(zhuǎn)換(默認(rèn)采用utf-8方式轉(zhuǎn)換)
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
console.log(buf_4);
console.log('-------');
//1-字符串轉(zhuǎn)換 默認(rèn)采用utf-8方式轉(zhuǎn)換
const str = buf_4.toString();
console.log(str);
元素的讀取以及修改
[]進(jìn)行單個(gè)元素的讀取以及修改大于255的值,溢出,舍棄高位,留下后8位二進(jìn)制utf-8編碼方式,1個(gè)漢字對(duì)應(yīng)3個(gè)字節(jié)
let buf_5 = Buffer.from('hello');
//1-[]括號(hào)方式進(jìn)行單個(gè)元素的查看 二進(jìn)制轉(zhuǎn)換的查看
console.log(buf_5[0]);//打印出十進(jìn)制
console.log(buf_5[0].toString(2));//實(shí)際上是01101000
//2-單個(gè)元素的修改
// 直接修改
buf_5[0] = 95;
//查看修改后的字符串的值
console.log(buf_5.toString());//輸出_ello
//溢出
buf_5[0] = 361;//舍棄高位超出8位的數(shù)字 0001 0110 1001
console.log(buf_5);//69 0001被舍棄,留下0110 1001
//中文
let buf_6 = Buffer.from('你好');//utf-8編碼方式 1個(gè)漢字對(duì)應(yīng)3個(gè)中文
console.log(buf_6);//輸出
計(jì)算機(jī)基礎(chǔ)
計(jì)算機(jī)基本組成
CPU 中央處理器,運(yùn)算與控制的核心。工作時(shí)會(huì)產(chǎn)生大量熱量,一般連接一個(gè)散熱器進(jìn)行散熱。內(nèi)存 讀寫速度較快,斷電丟失數(shù)據(jù)硬盤 讀寫速度較慢,斷電不丟失數(shù)據(jù)主板 CPU 內(nèi)存 硬盤 通過主板連接在一起顯卡 負(fù)責(zé)處理視頻信號(hào),有信息需要在顯示器呈現(xiàn),就會(huì)將信號(hào)傳遞到顯卡,顯卡處理完畢再將信號(hào)傳遞給顯示器,顯示器最終顯示
程序運(yùn)行基本流程
安裝好上面CPU等,還需安裝操作系統(tǒng)方可運(yùn)行。 操作系統(tǒng):
操作系統(tǒng)也是一種應(yīng)用程序,用來管理和調(diào)度硬件資源。將操作系統(tǒng)安裝到硬盤,電腦即可開機(jī)運(yùn)行。 常見操作系統(tǒng)
WindowsLinuxMacOs 總結(jié):程序一般保存到硬盤中,軟件安裝的過程就是將程序?qū)懭胗脖P的過程。程序在運(yùn)行時(shí)會(huì)加載進(jìn)入內(nèi)存,然后由CPU讀取并執(zhí)行程序
進(jìn)程與線程
進(jìn)程包含一個(gè)或多個(gè)線程。進(jìn)程>線程
進(jìn)程
通俗理解為進(jìn)行中的程序進(jìn)程是程序的一次執(zhí)行過程
線程
線程是一個(gè)進(jìn)程中執(zhí)行的一個(gè)執(zhí)行流一個(gè)線程是屬于某個(gè)進(jìn)程的
fs模塊
全稱:file system 文件系統(tǒng)。fs模塊可以實(shí)現(xiàn)與硬盤的交互。 例如文件的創(chuàng)建、刪除、重命名、移動(dòng),還有文件內(nèi)容的寫入、讀取,以及文件夾的操作。
寫入文件
語法: fs.writeFile(file,data[,option],callback)
同步與異步
異步:情況比如做飯,按下了煮飯鍵就去炒菜。同步:類似排隊(duì),一個(gè)完成接著一個(gè)。對(duì)效率要求高的基本都是用異步API。
異步寫入語法: fs.writeFile(file,data[,option],callback)同步寫入語法: fs.writeFileSync(file,data[,option])
/** 需求
* 新建一個(gè)文件夾為座右銘.txt(info.txt)
* 寫入內(nèi)容為 三人行,必有我?guī)熝伞?/p>
*/
const fs = require("fs");
//寫入文件 異步寫入
fs.writeFile('./info.txt', '三人行,必有我?guī)熝桑?, (err) => {
if (err) {
console.error("寫入錯(cuò)誤:")
console.error(err);
return;
}
console.log("寫入成功!")
})
//寫入文件
// 同步寫入
fs.writeFileSync('./infoSync.txt', '測(cè)試同步寫入');
// 流式寫入
const ws = fs.createWriteStream('./writeStream.txt');
ws.write('床前明月光\r\n');
ws.write('疑是地上霜\r\n');
ws.write('舉頭望明月\r\n');
ws.write('低頭思故鄉(xiāng)\r\n');
//關(guān)閉
ws.end();
文件追加寫入
文件追加多用于程序日志,不斷往文件追加內(nèi)容
方法說明fs.appendFile(file,data[,option],callback)異步追加fs.appendFileSync(file,data[,option])同步追加fs.writeFile(file,data[,option],callback)添加標(biāo)識(shí)異步追加option為{flag:'a'}
// 文件追加寫入
const fs = require('fs');
// 異步追加
fs.appendFile('./info.txt', '\r\n哈哈哈追加內(nèi)容下!', err => {
if (err) {
console.error(err);
return;
}
console.log('追加內(nèi)容成功!')
})
//同步追加內(nèi)容
fs.appendFileSync('./infoSync.txt', '\r\n同步追加內(nèi)容看看!');
// 異步追加內(nèi)容
fs.writeFile('./info.txt', '\r\n哈哈哈writeFile追加!', {flag: 'a'}, err => {
if (err) {
console.error('追加錯(cuò)誤:');
console.error(err);
return;
}
console.log('追加成功!')
})
流式寫入
程序打開一個(gè)文件需要消耗資源,流式寫入可以減少文件的次數(shù)。 流式寫入方式適用于大文件寫入或者頻繁寫入的場(chǎng)景,writeFile適用于寫入頻率較低的場(chǎng)景。
流式讀?。p少連接次數(shù),連接后不斷開)語法:fs.createWriteStream(path[,option])
參數(shù)說明:
path 文件路徑options選項(xiàng)配置
返回值 Object
代碼示例:
//寫入文件
// 同步寫入
fs.writeFileSync('./infoSync.txt', '測(cè)試同步寫入');
// 流式寫入
const ws = fs.createWriteStream('./writeStream.txt');
ws.write('床前明月光\r\n');
ws.write('疑是地上霜\r\n');
ws.write('舉頭望明月\r\n');
ws.write('低頭思故鄉(xiāng)\r\n');
//關(guān)閉
ws.end();
文件寫入應(yīng)用場(chǎng)景
當(dāng)需要持久化保存數(shù)據(jù)的時(shí)候,應(yīng)該想到文件寫入
下載文件安裝軟件保存程序日志,如Git編輯器保存文件視頻錄制
文件讀取
程序從文件中取出其中的數(shù)據(jù)。
方法說明fs.readFile(file,data[,option],callback)異步讀取fs.readFileSync(file,data[,option])同步讀取fs.createReadStream(file,data[,option],callback)流式讀取
代碼示例:
// 文件讀取
const fs = require('fs');
// 異步讀取
fs.readFile('./info.txt', (err, data) => {
if (err) {
console.error('讀取錯(cuò)誤:');
console.error(err);
return;
}
console.log('讀取成功!')
console.log(data.toString());
})
console.log('-----------------');
// 同步讀取
const readDataSync = fs.readFileSync('./infoSync.txt');
console.log('同步讀取:')
console.log(readDataSync.toString());
console.log('-----------------');
// 流式讀取
// 創(chuàng)建視頻流對(duì)象
const rs = fs.createReadStream('./writeStream.txt');
// 綁定data事件 chunk 塊
rs.on('data', chunk => {
console.log('---------!!----------');
// 字符串類文件讀取可以,要是讀取的的mp4文件,用toString輸出將會(huì)亂碼,直接console.log(chunk)即可
console.log(chunk.toString());
console.log('---------!!----------');
})
// end可選事件
rs.on('end', () => {
console.log('流式讀取完成!');
})
讀取文件應(yīng)用場(chǎng)景
電腦開機(jī)程序運(yùn)行編輯器打開文件查看圖片播放視頻播放音樂Git查看日志上傳文件查看聊天記錄
fs練習(xí)_復(fù)制文件
代碼示例:
/** fs練習(xí)_復(fù)制文件
* 將writeSteam.txt內(nèi)容復(fù)制,新建writeStreamCopy.txt
*/
// 思路
// 1- readFile讀取內(nèi)容
// 2- writeFile新建文件
// 1、同步讀取寫入
const fs = require('fs');
// 讀取
const readDataCopy = fs.readFileSync('./writeStream.txt');
// 寫入
fs.writeFileSync('./writeStreamCopy.txt', readDataCopy);
console.log('測(cè)試內(nèi)存:');
// PS:注釋下面流式讀取 得出內(nèi)存
console.log(process.memoryUsage());// 28119040字節(jié) ?1024 約等于 281366.25kb ?1024 約等于 274.78Mb
console.log('------------------------');
// 2、流式讀取寫入
//創(chuàng)建讀取流對(duì)象
const rsCopy = fs.createReadStream('./writeStream.txt');
// 創(chuàng)建寫入流對(duì)象
const wsCopy = fs.createWriteStream('./writeStreamCopyStream.txt');
// 1-綁定data事件
rsCopy.on('data', chunk => {
wsCopy.write(chunk);
})
// 2-on('data')方法復(fù)制或直接使用 管道 直接復(fù)制
// rsCopy.pipe(wsCopy);
// rsCopy.on('end', () => {
// console.log('測(cè)試內(nèi)存:');
// // PS:注釋上面直接讀取 得出內(nèi)存
// console.log(process.memoryUsage());// 28434432字節(jié) ?1024 約等于 27768kb ?1024 約等于 27.117Mb
// console.log('------------------------');
// })
文件重命名和移動(dòng)
異步移動(dòng)語法 fs.rename(oldPath,newPath,callback)同步移動(dòng)語法fs.renameSync(oldPath,newPath)
參數(shù)說明
oldPath:文件當(dāng)前路徑newPath:文件新的路徑callback:操作后的回調(diào)
代碼示例:
// fs重命名
const fs = require('fs');
//重命名:將文件1重命名為infoRename.txt
fs.rename('./info.txt', './infoRename.txt', err => {
if (err) {
console.error('重命名失敗:');
console.error(err);
return;
}
console.log('重命名成功!');
})
// 確保目標(biāo)目錄存在
if (!fs.existsSync('./file')) {
fs.mkdirSync('./file');
}
// 移動(dòng):將重命名后的文件1移動(dòng)到file文件夾,命名為info.txt
fs.rename('./infoSync.txt', './file/infoMove.txt', err => {
if (err) {
console.error('移動(dòng)失?。?);
console.error(err);
return;
}
console.log('移動(dòng)成功!');
})
文件刪除
異步刪除語法 fs.unlink(path,callback) 同步刪除語法fs.unlinkSync(path) 異步刪除fs.rm(path,callback) ps:node.js14.4版本以上才可用 同步刪除fs.rmSync(path) ps:node.js14.4版本以上才可用
參數(shù)說明:
path:文件路徑callback:操作后的回調(diào)
代碼示例:
// 文件刪除
const fs = require('fs');
//unlink刪除
fs.unlink('./info.txt', (err) => {
if (err) {
console.error(err);
return;
}
console.log('刪除成功!');
})
fs.unlinkSync('./infoSync.txt');
// rm刪除 node.js14.4版本以上
fs.rm('./writeStream.txt', (err) => {
if (err) {
console.error(err);
return;
}
console.log('刪除成功2!');
})
fs.rmSync('./writeStreamCopyStream.txt');
文件夾操作
創(chuàng)建文件夾mkdir/mkdirSync讀取文件夾readdir/readdirSync刪除文件夾rmdir/rmdirSync
方法說明mkdir/mkdirSync創(chuàng)建文件夾readdir/readdirSync讀取文件夾rmdir/rmdirSync刪除文件夾
PS:判斷文件夾是否存在
同步判斷語法 fs.existsSync(path[,option])
參數(shù)說明:
path:文件路徑
創(chuàng)建文件夾
異步創(chuàng)建語法:fs.mkdir(path,callback)同步創(chuàng)建語法:fs.mkdirSync(path)
代碼示例:
// 文件夾操作_創(chuàng)建文件夾
const fs = require('fs');
// 創(chuàng)建文件
//先判斷是否存在
if (!fs.existsSync('./newFile')) {
fs.mkdir('./newFile', err => {
if (err) {
console.log('創(chuàng)建失?。?);
console.error(err);
return;
}
console.log('創(chuàng)建成功');
})
}
//先判斷是否存在
if (!fs.existsSync('./a/b/c', {recursive: true})) {
// 遞歸創(chuàng)建文件夾
fs.mkdir('./a/b/c', {recursive: true}, err => {
if (err) {
console.log('創(chuàng)建失敗2:');
console.error(err);
return;
}
console.log('創(chuàng)建成功2');
})
}
//先判斷是否存在
if (!fs.existsSync('./test2/d/e', {recursive: true})) {
fs.mkdirSync('./test2/d/e', {recursive: true});
}
讀取文件夾
異步讀取語法:fs.readdir(path,callback)同步讀取語法:fs.readdirSync(path)
參數(shù)說明:
path:路徑
代碼示例
// 文件夾操作——讀取文件夾
const fs = require('fs');
// 創(chuàng)建文件
fs.readdir('./newFile', (err, data) => {
if (err) {
console.log('讀取文件夾失?。?);
console.error(err);
return;
}
console.log('讀取文件夾成功');
console.log(data);
})
// 讀取文件夾
fs.readdir('./file', (err, data) => {
if (err) {
console.log('讀取文件夾失敗2:');
console.error(err);
return;
}
console.log('讀取文件夾成功2');
console.log(data);
})
const readfileData = fs.readdirSync('./test2');
console.log('同步讀取文件夾');
console.log(readfileData);
刪除文件夾
不推薦使用rmdir
異步刪除語法:fs.rmdir(path,callback)同步刪除語法:fs.rmdirSync(path)
推薦使用rm:
異步刪除語法:fs.rm(path,callback)同步刪除語法:fs.rmSync(path)
參數(shù)說明:
path:路徑
代碼示例:
// 刪除文件夾
const fs = require('fs');
//遞歸刪除 不推薦使用rmdir 推薦使用rm
fs.rmdir('./a',{ recursive: true }, (err) => {
if(err){
console.log('刪除文件夾出錯(cuò)');
console.error(err);
return;
}
console.log('刪除文件夾成功!');
})
fs.rmdirSync('./test2', {recursive: true});
//rm刪除
fs.rm('./newFile',{ recursive: true }, (err) => {
if(err){
console.log('刪除文件夾出錯(cuò)2:');
console.error(err);
return;
}
console.log('刪除文件夾成功2!');
})
fs.rmSync('./test', {recursive: true});
查看資源狀態(tài)
異步查看語法:fs.stat(path[,option],callback)同步查看語法: fs.statSync(path[,option])
參數(shù)說明:
path 文件路徑options 選項(xiàng)配置(可選)callback 操作后的回調(diào)
示例代碼:fs_stat.js
/** 查看資源狀態(tài)
* fs.stat()
*/
const fs = require('fs');
// 異步獲取狀態(tài)
fs.stat('./info.txt', (err, data) => {
if(err){
console.log('查看資源失?。?)
console.log(err);
return;
}
console.log('異步查看資源成功!詳細(xì)信息如下:')
console.log(data);
//判斷是否是一個(gè)文件方法 isFile()
console.log('是文件嗎?')
console.log(data.isFile());
// 判斷是否是一個(gè)文件夾方法 isDirectory()
console.log("是文件夾嗎?")
console.log(data.isDirectory());
})
// 同步獲取狀態(tài)
const data = fs.statSync('./info.txt');
console.log('同步查看資源成功!詳細(xì)信息如下:')
console.log(data);
結(jié)果值對(duì)象結(jié)構(gòu):
size 文件體積birthtime 創(chuàng)建時(shí)間mtime 最后修改時(shí)間isFile 檢測(cè)是否為文件isDirectory 檢測(cè)是否為文件夾…
路徑補(bǔ)充說明
路徑分為相對(duì)路徑和絕對(duì)路徑兩種寫法
相對(duì)路徑
比如在當(dāng)前根目錄的info.txt
相對(duì)路徑表達(dá)為./info.txt
相對(duì)路徑常遇到的bug與解決
相對(duì)路徑參照的是命名行的工作目錄!
Bug:
比如在 代碼利用相對(duì)路徑創(chuàng)建文件./info.txt:
在當(dāng)前命令運(yùn)行node fs_writeFile.js就在當(dāng)前文件夾生成info.txt在nodejs上層運(yùn)行node ./nodejs/fs_writeFile.js就會(huì)在nodejs同級(jí)生成info.txt
結(jié)論:
相對(duì)路徑的參照物 是在運(yùn)行命令行的當(dāng)前目錄
解決方法
利用絕對(duì)路徑:使用全局變量__dirname進(jìn)行拼接:保存的是所在文件的所在目錄的絕對(duì)路徑
代碼示例:
//使用絕對(duì)路徑:__dirname拼接方式
//利用絕對(duì)路徑:使用全局變量`__dirname`進(jìn)行拼接:保存的是所在文件的所在目錄的`絕對(duì)路徑`
fs.writeFileSync(__dirname+'/index.html','寫入內(nèi)容哈哈哈哈')
絕對(duì)路徑
常會(huì)遇到權(quán)限的問題
比如在D盤下的info.txt
絕對(duì)路徑表達(dá)為D:/info.txtlinux操作系統(tǒng)下用的較多/開頭,比如/info.txt
fs練習(xí)_批量重命名
優(yōu)化如下:
視頻用的是split會(huì)拆分,這里我用的是正則表達(dá)式視頻用的是相對(duì)路徑,這里我拼接了__dirname使用了絕對(duì)路徑
示例代碼:
/** 批量重命名
* 需求:將code文件夾里面的文件
* 名稱為前面為1-9的命名為01-09
*/
// 思路
// 1-讀取readdirSync里面的文件名稱 fs.readdirSync(path,callback)
// 2-重命名renameSync fs.renameSync(path,callback)
const fs = require('fs');
const files = fs.readdirSync(__dirname + '/code');
console.log('名稱為:');
console.log(files);
// 讀取文件修改
files.forEach(file => {
const oldPath = __dirname + '/code/' + file;
// 利用正則表達(dá)式_前面是一位數(shù)的補(bǔ)0
const newFileName = file.replace(/^(\d)_(.+)$/i, "0$1_$2");
const newPath = __dirname + '/code/' + newFileName;
//重命名
fs.renameSync(oldPath, newPath);
})
path模塊
path模塊提供了操作路徑的功能。
常用API如下:
API說明path.resolve拼接規(guī)范的絕對(duì)路徑 常用path.sep獲得操作系統(tǒng)的路徑分隔符path.parse解析路徑并返回對(duì)象path.basename獲得路徑基礎(chǔ)名稱path.dirname獲得路徑目錄名path.extname獲得路徑擴(kuò)展名
resolve(重點(diǎn)掌握)
代碼示例:
// path模塊
const fs = require('fs');
const path = require('path');
// 寫入文件
// 建議絕對(duì)路徑 +拼接+ 相對(duì)路徑 寫法 path.resolve(絕對(duì)路徑+相對(duì)路徑)
fs.writeFileSync(path.resolve(__dirname, './test.txt'), 'peace and love');
// 不建議這樣寫 最好不要 絕對(duì)路徑+絕對(duì)路徑寫法 /path為絕對(duì)路徑
// 這樣寫的意思是 /path的絕對(duì)路徑 +拼接+ ./test.txt
// fs.writeFileSync(path.resolve(__dirname, '/path', './test.txt'), 'peace and love');
運(yùn)行命令
node ./path/path.js
sep
sep分隔符 :不同操作系統(tǒng)的分隔符不同,獲取不同操作系統(tǒng)下的分隔符
操作系統(tǒng)分隔符windows\linux/macos/
代碼示例:
const path = require('path');
// sep分隔符 :不同操作系統(tǒng)的分隔符不同,獲取不同操作系統(tǒng)下的分隔符
console.log(path.sep); //windows:\ linux:/ macos:/
path
解析路徑返回對(duì)象=》語法: path.parse(path)
參數(shù)說明:
path:文件解析路徑
代碼示例:
// parse 解析路徑并返回對(duì)象
// 查看當(dāng)前文件路徑
console.log(__filename);
//定義路徑
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 解析路徑
console.log(path.parse(str));
basename
獲得文件名=》語法: path.basename(path)
參數(shù)說明:
path:文件解析路徑
代碼示例:
// basename 獲取路徑名稱
// 查看當(dāng)前文件路徑
console.log(__filename);
//定義路徑
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 獲取的文件名
console.log(path.basename(str)); //path.js
dirname
獲得文件夾的目錄名=》語法: path.dirname(path)
參數(shù)說明:
path:文件解析路徑
代碼示例:
// dirname 獲取文件目錄名
// 查看當(dāng)前文件路徑
console.log(__filename);
//定義路徑
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 獲取文件目錄名
console.log(path.dirname(str)); // /Users/lhm/Documents/nodejs/path
extname
獲得文件擴(kuò)展名(即為后綴名)=》語法: path.extname(path)
參數(shù)說明:
path:文件解析路徑
代碼示例:
// extname 獲取文件擴(kuò)展名即為后綴名
// 查看當(dāng)前文件路徑
console.log(__filename);
//定義路徑
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 獲取文件擴(kuò)展名
console.log(path.extname(str)); // .js
HTTP協(xié)議
初識(shí)
全稱 Hypertext Transfer Protocol 超文本傳輸協(xié)議 互聯(lián)網(wǎng)應(yīng)用最廣泛的協(xié)議之一協(xié)議:雙方必須共同遵從的一組約定瀏覽器 輸入 url 給服務(wù)器發(fā)送 請(qǐng)求報(bào)文, 服務(wù)器 給 瀏覽器 發(fā)送響應(yīng)報(bào)文 進(jìn)行響應(yīng)
HTTP報(bào)文
安裝軟件fiddler 查看報(bào)文內(nèi)容,自行下載摸索。
請(qǐng)求報(bào)文結(jié)構(gòu)
請(qǐng)求行 GET https://www.baidu.com請(qǐng)求頭請(qǐng)求體
請(qǐng)求行
如 GET https://www.baidu.com/ HTTP/1.1
構(gòu)成
請(qǐng)求方法URLHTTP版本號(hào)
請(qǐng)求方法
常見方法如下:
方法作用GET主要用于獲取數(shù)據(jù)POST主要用于新增數(shù)據(jù)PUT/PATCH主要用于更新數(shù)據(jù)DELETE主要用于刪除數(shù)據(jù)HEAD/OPTIONS/CONNECT/TRACE使用相對(duì)較少
URL
全程 Uniform Resource Locator 統(tǒng)一資源定位符 比如:https://search.jd/com:443/search?keyword=oneplus&psort=12
協(xié)議名 https主機(jī)名 search.jd.com端口號(hào) 443路徑 /search查詢字符串 ?keyword=oneplus&psort=12
HTTP版本號(hào) 常見版本號(hào):
版本號(hào)發(fā)布時(shí)間1.01996年1.11999年22015年32018年
請(qǐng)求頭
很多鍵值對(duì)組成,主要是記錄瀏覽器很多相關(guān)的信息,記錄與瀏覽器交互的行為。
點(diǎn)擊跳轉(zhuǎn)MDN查看請(qǐng)求頭
請(qǐng)求體
用一個(gè)場(chǎng)景理解它。比如登錄場(chǎng)景 ,發(fā)送post請(qǐng)求傳過去的數(shù)據(jù):username=111&password=asaj11212。這些即為請(qǐng)求體。
響應(yīng)報(bào)文
響應(yīng)行響應(yīng)頭響應(yīng)體
響應(yīng)行
HTTP版本號(hào)響應(yīng)狀態(tài)碼響應(yīng)狀態(tài)的描述
響應(yīng)狀態(tài)碼
狀態(tài)碼含義200請(qǐng)求成功403禁止請(qǐng)求404找不到資源500服務(wù)器內(nèi)部錯(cuò)誤
響應(yīng)狀態(tài)的描述
響應(yīng)狀態(tài)的描述通常與狀態(tài)碼相關(guān)
狀態(tài)碼狀態(tài)描述200OK403Forbidden404Not Found500Internal Server Error
點(diǎn)擊查看更多狀態(tài)碼
響應(yīng)頭
跟請(qǐng)求頭一樣為鍵值對(duì)的形式,記錄與服務(wù)器相關(guān)的一些內(nèi)容。
點(diǎn)擊查看更多響應(yīng)頭
響應(yīng)體
響應(yīng)體即響應(yīng)的內(nèi)容
常見的響應(yīng)體格式有:
HTMLCSSJavaScript圖片視頻JSON
網(wǎng)絡(luò)基礎(chǔ)概念
IP
IP也稱為[IP地址],本身是一個(gè)數(shù)字標(biāo)識(shí)。例如 192.168.1.3。 通俗理解IP地址主要用來尋找網(wǎng)絡(luò)設(shè)備,本身是32Bit的二進(jìn)制數(shù)字。
作用:
IP用來標(biāo)識(shí)網(wǎng)絡(luò)中的設(shè)備,實(shí)現(xiàn)設(shè)備間的通信
IP的分類
類型說明本地回環(huán)IP地址127.0.0.1 ~ 127.255.255.255局域網(wǎng)IP(私網(wǎng)IP)192.168.0.0 ~ 192.168.255.255172.16.0.0~172.31.255.25510.0.0.0 ~ 10.255.255.255廣域網(wǎng)(公網(wǎng)IP)除上述之外
端口
端口:應(yīng)用程序的數(shù)字標(biāo)識(shí)。一臺(tái)現(xiàn)代計(jì)算機(jī)有65536個(gè)端口(0~65535)。一個(gè)應(yīng)用程序可以使用一個(gè)或多個(gè)端口。 通俗理解: 趕集的攤位的 編號(hào) 好比 計(jì)算機(jī)理解的端口
作用:
實(shí)現(xiàn)不同主機(jī)應(yīng)用程序之間的通信
http模塊
創(chuàng)建http服務(wù)端
代碼示例:./http/createServer.js
// 創(chuàng)建服務(wù)
// 1.導(dǎo)入http模塊
const http = require('http');
// 2.創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
//設(shè)置響應(yīng)內(nèi)容
response.end('Hello World! Hello node.js Server!');
});
// 3.監(jiān)聽端口,啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log("Server started on port 9000...");
console.log('http://localhost:9000/');
})
注意事項(xiàng)
命令行ctrl + c停止服務(wù)當(dāng)服務(wù)啟動(dòng)后,更新代碼必須重啟服務(wù)才能生效響應(yīng)內(nèi)容中文亂碼的解決方法
response.setHeader('content-type','text/html;charset=utf-8')
端口號(hào)被占用
關(guān)閉當(dāng)前正在運(yùn)行監(jiān)聽端口的服務(wù)使用較多修改其他端口號(hào)
HTTP協(xié)議默認(rèn)端口號(hào)是80。HTTP服務(wù)開發(fā)常用端口有3000,8080,8090,9000等
獲取http請(qǐng)求報(bào)文
想要獲取請(qǐng)求的數(shù)據(jù),需要通過request對(duì)象
含義語法重點(diǎn)掌握請(qǐng)求方法request.method*請(qǐng)求http協(xié)議版本request.httpVersion請(qǐng)求路徑request.url*請(qǐng)求頭request.headers*請(qǐng)求體request.on(‘data’,function(chunk){})request.on(‘end’,function(){});url請(qǐng)求路徑const url = require(‘url’); url.parse(request.url).pathname;*url查詢字符串const url = require(‘url’); url.parse(request.url,true).query;
注意事項(xiàng):
request.ur;只能獲取路徑以及查詢的字符串,無法獲取URL中的域名以及協(xié)議的內(nèi)容request.headers將請(qǐng)求信息轉(zhuǎn)化為一個(gè)對(duì)象,并將屬性名都轉(zhuǎn)換成了【小寫】關(guān)于路徑:如果訪問網(wǎng)站的時(shí)候,只寫了IP地址或者是域名信息,此時(shí)請(qǐng)求的路徑為【/】關(guān)于favicon.ico:這個(gè)請(qǐng)求是屬于瀏覽器自動(dòng)發(fā)送的請(qǐng)求
請(qǐng)求頭
代碼示例:./http/request_header.js
ps:瀏覽器打開form.html輸入提交進(jìn)行測(cè)試 ps:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。
// 請(qǐng)求報(bào)文之請(qǐng)求頭
//引入http模塊
const http = require("http");
//創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 1-----請(qǐng)求頭
//請(qǐng)求方法
console.log('請(qǐng)求方法');
console.log(request.method);
// 請(qǐng)求http版本
console.log('請(qǐng)求http版本');
console.log(request.httpVersion);
// 請(qǐng)求頭
console.log('請(qǐng)求url');
console.log(request.headers.host);
// 請(qǐng)求路徑
console.log('請(qǐng)求路徑');
console.log(request.url);
})
//啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
請(qǐng)求體
代碼示例:./http/request_content.js
ps:瀏覽器打開form.html輸入提交進(jìn)行測(cè)試 ps:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。
// 請(qǐng)求報(bào)文之請(qǐng)求體
//引入http模塊
const http = require("http");
//創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// ----請(qǐng)求體
// 定義請(qǐng)求體內(nèi)容
let body = '';
request.on('data', (chunk) => {
body += chunk;
})
request.on('end', () => {
console.log('請(qǐng)求體內(nèi)容:')
console.log(body);
console.log('--------end--------------')
response.end('hello world!');
})
})
//啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
請(qǐng)求路徑與查詢關(guān)鍵字
方式1:通過內(nèi)置url解析
請(qǐng)求路徑語法:url.parse(request.url).pathname)查詢字符串語法:url.parse(request.url,true).query
注意事項(xiàng): 2. 運(yùn)行:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。 2. 在瀏覽器輸入進(jìn)行測(cè)試觀察終端打印日志:點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試
代碼示例:./http/request_url.js
// 請(qǐng)求報(bào)文之url
//引入http模塊
const http = require("http");
const url = require("url");
//創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// ----url
console.log('請(qǐng)求路徑:')
console.log(url.parse(request.url).pathname);
console.log('查詢字符串:')
console.log(url.parse(request.url,true).query);
console.log(url.parse(request.url,true).query.username);
console.log(url.parse(request.url,true).query.password);
console.log('---------------');
response.end('hello world!');
})
//啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
方式2:通過new URL解析
語法:new URL(input[,base]) 點(diǎn)擊了解更多new URL英文 點(diǎn)擊了解更多new URL中文
注意事項(xiàng):
運(yùn)行:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。在瀏覽器輸入進(jìn)行測(cè)試觀察終端打印日志:點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試
代碼示例:./http/request_newURL.js
// 請(qǐng)求報(bào)文之url
//引入http模塊
const http = require("http");
//創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 2- 通過new URL方式獲取
let url = new URL(request.url, 'http://localhost:9000');
console.log(url);
console.log('請(qǐng)求路徑:')
console.log(url.pathname);
console.log('查詢字符串');
console.log(url.searchParams.get('username'));
console.log('------------------')
})
//啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
http請(qǐng)求練習(xí)
注意事項(xiàng):
運(yùn)行:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。在瀏覽器輸入進(jìn)行測(cè)試觀察終端打印日志:
登錄頁面:點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試注冊(cè)頁面:點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試不存在:點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試
/** http練習(xí)
* 需求
* 請(qǐng)求類型 get 地址/login 返回 “登錄頁面” 四字
* 請(qǐng)求類型 get 地址/reg 返回 “注冊(cè)頁面” 四字
*/
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'GET') {
let url = new URL(req.url, 'http://127.0.0.1:9000');
//設(shè)置中文防止亂碼
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
if (url.pathname === '/login') {
res.end('登錄頁面');
} else if (url.pathname === '/reg') {
res.end('注冊(cè)頁面');
} else {
res.end('您當(dāng)前訪問頁面不存在!');
}
} else {
res.end('您當(dāng)前訪問頁面不存在!');
}
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000,');
})
設(shè)置http響應(yīng)報(bào)文
作用語法設(shè)置響應(yīng)狀態(tài)碼response.statusCode設(shè)置響應(yīng)狀態(tài)描述response.statusMessage(用的非常少)設(shè)置響應(yīng)頭信息response.setHeader(‘頭名’,‘頭值’)設(shè)置響應(yīng)體response.write(‘xx’);response.end(‘xx’);
注意事項(xiàng):
運(yùn)行:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。在瀏覽器輸入此url進(jìn)行請(qǐng)求,打開瀏覽器——右鍵檢查——查看網(wǎng)絡(luò):
點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試
代碼示例:
// 設(shè)置響應(yīng)頭
//引入http模塊
const http = require("http");
//創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 設(shè)置響應(yīng)
//響應(yīng)狀態(tài)碼
response.statusCode = 200;
//設(shè)置響應(yīng)狀態(tài)信息
response.statusMessage = 'iloveyou';
// 設(shè)置響應(yīng)頭
// 設(shè)置編碼格式 防止中文亂碼
response.setHeader('content-type', 'text/html; charset=utf-8');
// 自定義響應(yīng)頭
response.setHeader('myHeaders', 'Authorization');
//響應(yīng)體 write可有多個(gè)
response.write('哈哈哈哈 響應(yīng)體');
response.write('哈哈哈哈2 響應(yīng)體');
// 響應(yīng)體 end 只有一個(gè)
response.end('bye!!')
});
//啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
http響應(yīng)練習(xí)
注意事項(xiàng):
運(yùn)行:當(dāng)端口被占用,關(guān)閉其它運(yùn)行9000端口的終端,或者修改運(yùn)行端口號(hào)。在瀏覽器輸入此url進(jìn)行請(qǐng)求查看效果:
點(diǎn)擊跳轉(zhuǎn)瀏覽器進(jìn)行測(cè)試
代碼示例:res.pratice.html + res_pratice.js
/** http響應(yīng)練習(xí)
* 需求
* 搭建http服務(wù),響應(yīng)一個(gè)4行3列的表格
* 并且要求表格有 隔行換色效果,且點(diǎn)擊單元格能高亮顯示
*/
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
res.setHeader('content-type', 'text/html;charset=UTF-8');
const html = fs.readFileSync(__dirname+'/res_pratice.html');
res.end(html);
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000/');
})
網(wǎng)頁資源加載的全部過程
1-先加載html 2-再根據(jù)html內(nèi)容加載css、圖片資源、js等 3-favicon.icon請(qǐng)求:瀏覽器默認(rèn)行為:默認(rèn)請(qǐng)求網(wǎng)站圖標(biāo)favicon.icon 4-ws請(qǐng)求:插件行為,使得網(wǎng)頁實(shí)現(xiàn)自動(dòng)刷新功能
實(shí)現(xiàn)網(wǎng)頁引入外部資源
接回之前的響應(yīng)練習(xí),現(xiàn)在需求是將css js分離開,單獨(dú)引入資源
代碼示例: res_pratice.js => 讀取res_practice.html res_pratice.css pratice_click.js
/** http響應(yīng)練習(xí)
* 需求
* 搭建http服務(wù),響應(yīng)一個(gè)4行3列的表格
* 并且要求表格有 隔行換色效果,且點(diǎn)擊單元格能高亮顯示
*/
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
//按路徑區(qū)分 請(qǐng)求資源 進(jìn)行 響應(yīng)。不要都響應(yīng)此html
const {pathname} = new URL(req.url, 'http://127.0.0.1')
if (pathname === '/') {
//注意:此響應(yīng)頭得在html里,否則可能會(huì)沒效果
res.setHeader('content-type', 'text/html;charset=UTF-8');
const html = fs.readFileSync(__dirname + '/res_pratice.html');
res.end(html);
} else if (pathname === '/res_pratice.css') {
const css = fs.readFileSync(__dirname + '/res_pratice.css');
res.end(css);
} else if (pathname === '/pratice_click.js') {
const js = fs.readFileSync(__dirname + '/pratice_click.js');
res.end(js);
} else {
res.end('
404 Not Found!
');}
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000/');
})
靜態(tài)資源與動(dòng)態(tài)資源
靜態(tài)資源:內(nèi)容長(zhǎng)時(shí)間不發(fā)生改變的資源,例如圖片,視頻,css文件,js文件,HTML文件,字體文件等動(dòng)態(tài)資源:內(nèi)容經(jīng)常更新的資源,例如百度首頁,網(wǎng)易首頁,京東搜索列表頁面等。
搭建靜態(tài)資源服務(wù)
對(duì)響應(yīng)式練習(xí)的優(yōu)化處理
利用__dirname+pathname進(jìn)行拼接,無需多次請(qǐng)求
代碼示例:
/** http響應(yīng)練習(xí)
* 需求
* 搭建http服務(wù),響應(yīng)一個(gè)4行3列的表格
* 并且要求表格有 隔行換色效果,且點(diǎn)擊單元格能高亮顯示
*/
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
//按路徑區(qū)分 請(qǐng)求資源 進(jìn)行 響應(yīng)。不要都響應(yīng)此html
// const {pathname} = new URL(req.url, 'http://127.0.0.1')
// if (pathname === '/') {
// //注意:此響應(yīng)頭得在html里,否則可能會(huì)沒效果
// res.setHeader('content-type', 'text/html;charset=UTF-8');
// const html = fs.readFileSync(__dirname + '/res_pratice.html');
// res.end(html);
// } else if (pathname === '/res_pratice.css') {
// const css = fs.readFileSync(__dirname + '/res_pratice.css');
// res.end(css);
// } else if (pathname === '/pratice_click.js') {
// const js = fs.readFileSync(__dirname + '/pratice_click.js');
// res.end(js);
// } else {
// res.end('
404 Not Found!
');// }
// 優(yōu)化
const {pathname} = new URL(req.url, 'http://127.0.0.1')
const filename = pathname === '/' ? __dirname + '/res_pratice.html' : __dirname + pathname;
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
res.end('
404 Not Found!
');console.error(err);
return;
}
res.end(data);
})
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000/');
})
網(wǎng)頁URL之絕對(duì)路徑
絕對(duì)路徑可靠性強(qiáng),而且相對(duì)性容易理解,在項(xiàng)目中運(yùn)用較多
形式特點(diǎn)http://www.baidu.com直接向目標(biāo)資源發(fā)送請(qǐng)求,容易理解。網(wǎng)站的外鏈會(huì)用到此形式。//www.baidu.com與頁面URL的協(xié)議拼接形成完整URL再發(fā)送請(qǐng)求。大型網(wǎng)站用的比較多/web與頁面URL的協(xié)議、主機(jī)名、端口拼接形成完整URL再發(fā)送請(qǐng)求。中小型網(wǎng)站
網(wǎng)頁URL之相對(duì)路徑
相對(duì)路徑在發(fā)送請(qǐng)求時(shí),需要與當(dāng)前頁面URL路徑進(jìn)行計(jì)算,得到完整URL后,再發(fā)送請(qǐng)求,學(xué)習(xí)階段用的較多。 例如當(dāng)前網(wǎng)頁url為:http://www.atguigu.com/course/h5.html
形式最終的URL./css/app.csshttp://www.atguigu.com/course/css/app.cssjs/app/jshttp://www.atguigu.com/course/js/app.js…/img/logo.pnghttp://www.atguigu.com/img/logo.png…/mp4/show.mp4http://www.atguigu.com/mp4/show.mp4
網(wǎng)頁中使用URL的場(chǎng)景小結(jié)
包括但不限于以下場(chǎng)景:
a標(biāo)簽hreflink標(biāo)簽hrefscript標(biāo)簽srcimg標(biāo)簽srcvideo audio 標(biāo)簽 srcform中的actionAJAX請(qǐng)求中的URL
設(shè)置mime類型
媒體類型 通常稱為Multipurpose Internet Mail Extension 或 MIME 類型)是一種標(biāo)準(zhǔn),用來表示文檔、文件或字節(jié)流的性質(zhì)和格式。
mime 類型結(jié)構(gòu): [type]/[subType]
例如: text/html images/jpeg image/png application/json
HTTP服務(wù)可以設(shè)置響應(yīng)頭Content-Type來表明響應(yīng)體的MIME類型,瀏覽器會(huì)根據(jù)該類型決定如何處理資源 下面是常見的文件對(duì)應(yīng)的mime類型
html: `text/html`
css:`text/css`
js:`text/javascript`
png:`images/png`
jpg:`images/jpeg`
gif:`images/gif`
mp4:`video/mp4`
mp3:`audio/mpeg`
json:`application/json`
對(duì)于未知的資源類型,可選擇application/actet-stream類型,瀏覽器在遇到該類型響應(yīng)時(shí),會(huì)對(duì)該響應(yīng)體類型進(jìn)行獨(dú)立存儲(chǔ),也就是我們常見的下載效果
代碼示例:./http/mime.js
// 設(shè)置mime
const http = require('http');
const path = require('path');
const server = http.createServer((req, res) => {
// 優(yōu)化
const {pathname} = new URL(req.url, 'http://127.0.0.1');
const filepath = pathname === '/' ? __dirname + '/res_pratice.html' : __dirname + pathname;
// 得到后綴名
const extname = path.extname(filepath).slice(1);
// 根據(jù)請(qǐng)求文件后綴名,設(shè)置相應(yīng)的mime
let mimes = {
html: 'text/html',
css: "text/css",
js: 'text/javascript',
png: 'images/png',
jpg: 'images/jpeg',
gif: 'images/gif',
mp4: 'video/mp4',
mp3: 'audio/mp3',
json: 'application/json'
}
// 獲取對(duì)應(yīng)類型
const type = mimes[extname];
// 判斷
if (type) {
//解決亂碼問題
if(extname==='html'){
res.setHeader('Content-Type', type+';charset=utf-8');
}else{
res.setHeader('Content-Type', type);
}
} else {
res.setHeader('Content-Type', 'application/actet-stream');
}
fs.readFile(filepath, 'utf8', (err, data) => {
if (err) {
res.end('
404 Not Found!
');console.error(err);
return;
}
res.end(data);
})
});
server.listen(9000, () => {
console.log('server started');
console.log('http://localhost:9000/');
})
解決亂碼問題
html添加字符集charset:utf-8即可.響應(yīng)頭的字符集優(yōu)先于html的meta設(shè)置的字符集
代碼示例:如上:./http/mime.js
完善錯(cuò)誤處理
點(diǎn)擊node.js中文網(wǎng)查看錯(cuò)誤代碼具體含義
代碼處理示例:error.js
// 完善錯(cuò)誤處理
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res) => {
// 優(yōu)化
const {pathname} = new URL(req.url, 'http://127.0.0.1');
const filepath = pathname === '/' ? __dirname + '/res_pratice.html' : __dirname + pathname;
fs.readFile(filepath, 'utf8', (err, data) => {
if (err) {
console.error(err);
switch (err.code) {
case 'ENOENT':
res.statusCode = 404;
res.end('
404 Not Found!
');case 'EPERM':
res.statusCode = 403;
res.end('
403 Forbidden!
');default:
res.statusCode = 500;
res.end('
Internal Server Error
');}
return;
}
res.end(data);
})
});
server.listen(9000, () => {
console.log('server started');
console.log('http://localhost:9000/');
})
GET和POST使用場(chǎng)景
GET請(qǐng)求場(chǎng)景:
在地址欄直接輸入url訪問點(diǎn)擊a鏈接link標(biāo)簽引入cssscript標(biāo)簽引入jsvideo與audio引入多媒體img標(biāo)簽引入圖片form標(biāo)簽中的method為get
POST請(qǐng)求中的請(qǐng)求
form標(biāo)簽中的method為postAJAX中的post請(qǐng)求
GET和POST請(qǐng)求區(qū)別
GET和POST是HTTP協(xié)議請(qǐng)求中的兩種方式,主要有以下區(qū)別:
作用:GET主要是用來獲取數(shù)據(jù),POST主要是用來提交數(shù)據(jù)參數(shù)位置:GET主要用來獲取數(shù)據(jù),POST主要用來提交數(shù)據(jù)安全性:POST請(qǐng)求相對(duì)GET安全一些,因?yàn)樵跒g覽器中會(huì)暴露在地址欄GET請(qǐng)求大小有限制,一般為2k,而POST請(qǐng)求則沒有大小限制
模塊化
什么是模塊化
將一個(gè)復(fù)雜的程序文件依據(jù)一定規(guī)則(規(guī)范)拆分成多個(gè)文件的過程稱之為模塊化 其中拆分出的每個(gè)文件就是一個(gè)模塊。模塊內(nèi)部的數(shù)據(jù)是私有的,不過模塊可以暴露內(nèi)部數(shù)據(jù)以使其它模塊使用
模塊化項(xiàng)目: 編碼時(shí)按照模塊一個(gè)個(gè)編碼的,整個(gè)項(xiàng)目就是一個(gè)模塊化的項(xiàng)目
模塊化好處:
防止命名沖突高復(fù)用性高維護(hù)性
模塊化初體驗(yàn)
Commonjs規(guī)范
代碼示例:me.js
// 聲明函數(shù)
function tiemo(){
console.log('timemo')
}
module.exports = tiemo;
代碼示例:index.js
//引入模塊
const tiemo = require('./me');
// 調(diào)用
tiemo();
運(yùn)行:
./module/index.js 是相對(duì)于當(dāng)前打開終端的目錄路徑,根據(jù)自己路徑找到index.js
node ./module/index.js
模塊暴露數(shù)據(jù)
方式1:module.exports = value方式2:module.exports = {value1,value2}方式3:export.name = value
?注意:不要直接exports = value ? 錯(cuò)誤寫法
代碼示例: me.js
// 聲明函數(shù)
function tiemo() {
console.log('timemo')
}
function niejiao() {
console.log('niejiao');
}
// 暴露數(shù)據(jù)
// module.exports = tiemo;
// 暴露數(shù)據(jù)2
module.exports = {
tiemo,
niejiao
}
// 暴露數(shù)據(jù)3
// exports.niejiao = niejiao;
// exports.tiemo = tiemo;
// 注意:不能使用 exports=value的形式暴露數(shù)據(jù)
// 因?yàn)槿缦孪嗟?/p>
// exports = module.exports = {tiemo: tiemo}
// exports.tiemo = tiemo;
代碼示例:index.js 調(diào)用
//引入模塊
const me = require('./me');
// 調(diào)用
me.tiemo();
me.niejiao();
導(dǎo)入模塊
在模塊中使用require傳入文件路徑即可使用文件
const test = require('./me.js');
require使用的一些注意事項(xiàng)
對(duì)于自己創(chuàng)建的模塊,導(dǎo)入時(shí)路徑建議寫相對(duì)路徑,不能省略./和../js和json文件導(dǎo)入時(shí)可以不用寫后綴,c/c++編寫的node擴(kuò)展文件也可不寫后綴,但一般用不到如果導(dǎo)入其他類型的文件,會(huì)以js文件進(jìn)行處理如果導(dǎo)入路徑為文件夾,首先會(huì)檢測(cè)package.json文件中main屬性對(duì)應(yīng)的文件,如果main屬性不存在,或者package.json不存在,則會(huì)檢測(cè)文件夾下的index.js和index.json.如果還是沒找到,就會(huì)報(bào)錯(cuò)導(dǎo)入node.js內(nèi)置模塊時(shí),直接require模塊的名字即可,無需加./和../
Node.js實(shí)現(xiàn)了CommonJS模塊化規(guī)范
導(dǎo)入模塊的基本流程
介紹require導(dǎo)入自定義模塊的基本流程
將相對(duì)路徑轉(zhuǎn)為絕對(duì)路徑,定位目標(biāo)文件緩存檢測(cè)讀取目標(biāo)文件代碼包裹為一個(gè)函數(shù)并執(zhí)行(自執(zhí)行函數(shù))。通過arguments.callee.toString()查看自執(zhí)行函數(shù)緩存模塊的值返回module.exports值
CommonJS規(guī)范
module.exports exports 以及require 這些都是CommonJS模塊化規(guī)范中的內(nèi)容Node.js是實(shí)現(xiàn)了CommonJS模塊化規(guī)范,二者關(guān)系有點(diǎn)像JavaScript與ECMAScript
包管理工具
包管理工具就像哆啦A夢(mèng)
介紹
【包】英文單詞 package 代表了一組特定功能的源碼集合
包管理工具 管理【包】的應(yīng)用軟件,可以對(duì)【包】進(jìn)行下載安裝,更新,刪除,上傳等操作
常用的包管理工具
npmyarncnpm
npm安裝與介紹
node.js在安裝時(shí)會(huì)自動(dòng)安裝npm,若你已經(jīng)安裝了node.js,可以直接使用npm
通過 npm -v查看版本號(hào)測(cè)試。顯示版本號(hào)即為成功,反之失敗
npm初始化包
我在此新建了npm文件夾,并切換終端目錄到npm,使用cd npm切換到npm文件夾也可。
npm init (根據(jù)問題回答~使用默認(rèn)就回車)
?注意:
中文和英文大寫命名不允許,默認(rèn)是文件夾的名稱,所以文件夾也不能用中文和大寫version版本號(hào)要求x.x.x形式定義,x必須是數(shù)字,默認(rèn)值1.0.0ISC證書與MIT證書功能上是相同的,關(guān)于開源證書擴(kuò)展閱讀:點(diǎn)擊查看package.json可以手動(dòng)創(chuàng)建以及修改使用npm init -y 或者npm init --yes 極速創(chuàng)建package.json
搜索包
方式2種
命令行 【npm s/search 關(guān)鍵字】網(wǎng)站搜索 網(wǎng)址是:https://www.npmjs.com
關(guān)于如何精準(zhǔn)找到需要的包 這個(gè)事情需要在實(shí)踐中不斷積累,通過看文章,看項(xiàng)目去學(xué)習(xí)積累
下載依賴包
npm install 簡(jiǎn)寫 npm i
require導(dǎo)入npm包基本流程
在當(dāng)前文件夾的node_modules中尋找同名的文件夾在上級(jí)目錄下的node_modules中尋找同名的文件夾,直至找到磁盤根目錄
生產(chǎn)環(huán)境與開發(fā)環(huán)境
開發(fā)環(huán)境是程序員 專門用來寫代碼 的環(huán)境,一般是指程序員的電腦,開發(fā)環(huán)境的項(xiàng)目一般只能是程序員自己訪問生產(chǎn)環(huán)境是項(xiàng)目代碼正式運(yùn)行的環(huán)境,一般是指正式的服務(wù)器電腦,生產(chǎn)環(huán)境的項(xiàng)目一般每個(gè)客戶都可以訪問
生產(chǎn)依賴與開發(fā)依賴
我們可以在安裝時(shí)設(shè)置區(qū)分依賴的類型,目前分為兩類
類型命令補(bǔ)充生產(chǎn)依賴npm i -S uniqnpm i --save uniq-S等效于–save -S是默認(rèn)選項(xiàng)包信息保存在package.json中的dependencies屬性開發(fā)依賴npm i -D lessnpm i --save-dev less-D等效于–save-dev -S是默認(rèn)選項(xiàng)包信息保存在package.json中的devDependencies屬性
比如蛋炒飯需要 大米 油 蔥 雞蛋 鍋 煤氣 鏟子 其中 鍋 煤氣 鏟子 屬于開發(fā)依賴,只在制作階段使用 而大米 有 蔥 雞蛋屬于生產(chǎn)依賴 在制作與最終食用都會(huì)用 所以開發(fā)依賴是只在開發(fā)階段使用的依賴包,而生產(chǎn)依賴是開發(fā)階段和最終上線運(yùn)行階段都用到的依賴包
npm全局安裝
npm i -g nodemon
全局安裝完成之后就可以在命令行的任何位置運(yùn)行nodemon命令 該命令作用是自動(dòng)重啟node應(yīng)用程序?!拘薷奈募a后不需關(guān)閉終端,重新運(yùn)行,會(huì)自動(dòng)監(jiān)測(cè)編譯】 使用nodemon運(yùn)行即可
nodemon ./fs/fs_writeFile.js
與此同時(shí)修改./fs/fs_writeFile.js文件會(huì)自動(dòng)編譯,不需要關(guān)閉重新運(yùn)行
?注意:
全局安裝命令不受工作目錄位置影響可以通過npm root -g 查看全局安裝包位置只有全局類的工具才適合全局安裝
環(huán)境變量path
命令行輸入命令會(huì)在當(dāng)前目錄尋找.exe或者.cmd后綴可執(zhí)行文件執(zhí)行,找到執(zhí)行,找不到則報(bào)錯(cuò)。 比如輸入QQ 會(huì)在當(dāng)前文件夾尋找 QQ.exe或者QQ.cmd的可執(zhí)行文件。找不到就去環(huán)境變量中找,所以路徑需配置在環(huán)境變量中。
安裝所有依賴
npm i / npm install
npm i
npm安裝指定版本的包
語法:npm i <包名@版本包> 示例:
npm i jquery@1.11.2
npm刪除包
npm remove / npm rnpm uninstall / npm uni 全局刪除示例:
npm remove -g modemon
局部刪除示例:
npm remove uniq
npm uninstall juery
npm命令配置別名
通過package.json中配置script
npm start 是項(xiàng)目中常用命令,用來啟動(dòng)命令??刹患?runnpm run 有自動(dòng)向上級(jí)目錄查找的特性,跟require函數(shù)一樣默認(rèn)對(duì)于陌生項(xiàng)目,我們可以先通過查看scripts屬性來參考項(xiàng)目的一些操作??煽吹皆趺催\(yùn)行項(xiàng)目、打包項(xiàng)目等
示例如:(配置了start啟動(dòng)命令)
{
"name": "test",
"version": "1.0.0",
"description": "學(xué)習(xí)npm",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node ./test.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"uniq": "^1.0.1"
}
}
2.運(yùn)行
npm run start
cnpm
介紹
cnpm淘寶搭建的npmjs.com的完整鏡像,也稱為【淘寶鏡像】,網(wǎng)址cnpm服務(wù)部署在國(guó)內(nèi)阿里云服務(wù)器上,可以提高的下載速度官網(wǎng)也提供了一個(gè)全局工具包c(diǎn)npm,操作命令與npm大體相同
安裝
npm install -g cnpm --registry=https://registry.npmmirror.com
操作命令
基本跟npm相同
功能命令初始化cnpm init安裝包c(diǎn)npm i uniqcnpm i -S uniqcnpm i -D uniqcnpm i -g nodemon安裝項(xiàng)目依賴cnpm i刪除cnpm r uniqcnpm uni uniq
配置淘寶鏡像
用npm可直接下載淘寶鏡像,配置方式有兩種
直接配置工具配置
直接配置
npm config set registry https://registry.npmmirror.com/
工具配置
安裝nrm
npm i -g nrm
修改鏡像
nrm use taobao
檢查是否配置成功
npm config list
PS: 檢查registry地址是否為https://reggistry/npmmirror.com/ 如果是則表明成功
補(bǔ)充說明:
建議使用第二種方式進(jìn)行鏡像配置,因?yàn)楹罄m(xù)修改起來會(huì)比較方便雖然cnpm可以提高速度,但是npm也可以通過淘寶鏡像進(jìn)行加速,所以npm使用率還是高于cnpm
yarn
介紹
yarn是Facebook在2016年推出的JavaScript推出的包管理工具 官網(wǎng)網(wǎng)址
特點(diǎn)
速度超快:yam 緩存了每個(gè)下載過的包,所以再次使用時(shí)無需重復(fù)下載。 同時(shí)利用并行下載以最大化資源利用率,因此安裝速度更快超級(jí)安全:在執(zhí)行代碼之前,yarn 會(huì)通過算法校驗(yàn)每個(gè)安裝包的完整性超級(jí)可靠:使用詳細(xì)、簡(jiǎn)潔的鎖文件格式和明確的安裝算法,yarn 能夠保證在不同系統(tǒng)上無差異的工作
安裝
npm i -g yarn
yarn常用命令
功能命令初始化yarn init / yarn init -y安裝包yarn add uniq 生產(chǎn)依賴yarn add less --dev 開發(fā)依賴yarn global add nodemon 全局安裝安裝項(xiàng)目依賴yarn刪除yarn remove uniq 刪除項(xiàng)目依賴包yarn global remove nodemon 全局刪除包運(yùn)行命令別名yarn <別名>
npm 和 yarn 選擇
大家可以根據(jù)不同場(chǎng)景進(jìn)行選擇
個(gè)人項(xiàng)目,根據(jù)個(gè)人喜好選擇公司項(xiàng)目:根據(jù)項(xiàng)目代碼選擇,可以選擇通過鎖文件判斷項(xiàng)目的包管理工具
npm 鎖文件是 package-lock.jsonyarn 鎖文件是 yarn.lock
包管理工具不要混用,切記,切記,切記
npm發(fā)布一個(gè)包
創(chuàng)建與發(fā)布
將自己開發(fā)的工具包發(fā)布到npm服務(wù)上,方便自己和其它開發(fā)者進(jìn)行使用,操作步驟如下:
創(chuàng)建文件夾,并創(chuàng)建文件main中index.js入口文件,在文件中聲明刪除,使用module.exports暴露
代碼示例:
function add(a, b) {
return a + b;
}
module.exports = {
add
}
npm初始化工具包npm init,package.json填寫包的信息(包名必須唯一)注冊(cè)賬號(hào)激活賬號(hào)(一定要激活賬號(hào))修改為官方鏡像
之前使用了別的鏡像,比如淘寶鏡像加速,不切回官方鏡像很可能會(huì)上傳失敗.
通過nrm方式切回官方鏡像: 沒安裝的先安裝: npm i -g nrm
切回官方鏡像: nrm use npm
登錄npm,按照要求登錄
npm login
提交發(fā)布包
npm publish
更新包
更新包中代碼測(cè)試代碼是否可用修改package.json中版本號(hào)發(fā)布更新
npm publish
刪除包
npm unpublish
不成功加上--force強(qiáng)制刪除
npm unpublish --force
刪除包需要一定條件,查看條件
你是包作者發(fā)布小于24小時(shí)大于24小時(shí)后,沒有其他包依賴,并且每周小于300下載量,并且只有一個(gè)維護(hù)者
包管理工具擴(kuò)展介紹
很多語言都有包管理工具。除了編程語言,操作系統(tǒng)層面也存在包管理工具。
語言包管理工具PHPcomposerPythonpipJavamavenGogo modJavaScriptnpm/yarn/cnpm/otherRubyrubyGems
操作系統(tǒng)也存在包管理工具,不過這個(gè)包指的是軟件包:
操作系統(tǒng)包管理工具網(wǎng)址Centoscomposerhttps://package.debian.org/stabel/Ubuntuapthttps://package.ubuntu.com /MacOShomeviewhttps://brew.sh /Windowschocolateyhttps://chocolatey.org
nvm介紹與使用
介紹
nvm 全稱 Node Version Manager 顧名思義用來管理node版本工具。方便切換不用版本的Node.js。一般項(xiàng)目中,新舊項(xiàng)目要求的node版本不同,建議使用nvm安裝node.js,方便切換
下載安裝
安裝太久,不知道哪個(gè)博文好使了,可以去網(wǎng)上尋找細(xì)致教程
windows的github下載地址選擇 nvm-setup.exe 下載即可
常用命令
命令說明nvm use available顯示可下載的Node.js版本nvm list顯示已安裝的版本nvm install 18.12.1安裝18.12.1版本的Node.jsnvm install latest安裝最新版本的Node.jsnvm uninstall 18.12.1刪除18.12.1版本的Node.jsnvm use 18.12.1切換18.12.1的Node.js
express
express介紹
官網(wǎng)介紹:expresss是一個(gè)基于Node.js平臺(tái)的極簡(jiǎn)、靈活的WEB應(yīng)用開發(fā)框架。官網(wǎng)網(wǎng)址.簡(jiǎn)單來說,express是一個(gè)封裝好的工具包,封裝了很多功能,便于我們開發(fā)WEB應(yīng)用。(HTTP服務(wù)) http模塊幫助我們搭建http服務(wù),給瀏覽器做出相應(yīng)服務(wù)端的功能,直接使用還是不太方面,于是我們借助express框架.
express路由
路由確定了應(yīng)用程序如何響應(yīng)客戶對(duì)特定端點(diǎn)的請(qǐng)求。
express依舊兼容之前的http的獲取請(qǐng)求及其響應(yīng)方法!
路由基本使用
一個(gè)路由有請(qǐng)求方法、路徑和回調(diào)函數(shù)組成 express中提供了一系列方法,可以很方便的使用路由 使用格式如下:
app.
PS:代碼中1-4方法使用,知識(shí)點(diǎn)
代碼示例:startlearn.js
// 初認(rèn)識(shí)express
// 引入模塊
const express = require('express');
// 創(chuàng)建應(yīng)用對(duì)象
const app = express();
const port = 3000;
// 1-創(chuàng)建路由 get方法
app.get('/home', (req, res) => {
res.end('hello world');
})
// 2-創(chuàng)建路由 get方法
app.post('/login', (req, res) => {
res.end('hello login');
})
//3- 無論get或post方法
app.all('/test', (req, res) => {
res.end('no matter methods');
})
//4-上面匹配不上的路由規(guī)則
app.all('*', (req, res) => {
res.end('404 No Found');
})
//監(jiān)聽端口 啟動(dòng)服務(wù)
app.listen(port, () => {
console.log('Express server started');
console.log('http://localhost:9000/');
})
獲取請(qǐng)求報(bào)文參數(shù)
說明原生http獲取express框架獲取獲取請(qǐng)求路徑pathconst url = require(‘url’); url.parse(request.url).pathname; / new URL(req.url,‘http://localhost:9000’).pathnamereq.path獲取請(qǐng)求參數(shù)const url = require(‘url’); url.parse(request.url,true).query;req.query獲取ipreq.connection.remoteAddressreq.ip獲取請(qǐng)求頭req.headers[‘host’]req.get(‘host’)
獲取路由參數(shù)
語法eg=》路徑/:id 通過req.params.id獲取路由參數(shù)
代碼示例:
const express = require('express');
const app = express();
//通配符 通過http://localhost:3000/login/1212121訪問即可知
app.get('/login/:id', (req, res) => {
// 獲取id
console.log(req.params.id);
res.end('login success!');
})
app.get('/', (req, res) => {
res.end('hello');
})
//監(jiān)聽端口 啟動(dòng)服務(wù)
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
})
路由參數(shù)練習(xí)
運(yùn)行后點(diǎn)擊測(cè)試 代碼示例如下:singer.json + params_pratice.js
/** 需求
* 通過路由id返回歌手名稱及其它名稱
*/
const express = require('express');
const app = express();
const fs = require('fs');
// 讀取歌手假數(shù)據(jù)json文件
const singersData = fs.readFileSync(__dirname + '/singers.json').toString();
app.get('/singer/:id', (req, res) => {
const {id} = req.params;
const matchData = JSON.parse(singersData).singers.find(item => item.id === Number(id));
res.setHeader('content-type', 'text/html; charset=utf-8');
if (matchData) {
res.end(`名稱:${matchData.singer_name},其它名稱:${matchData.other_name}`);
} else {
res.end('No Such a Singer');
}
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
})
一般響應(yīng)設(shè)置
設(shè)置響應(yīng)狀態(tài)碼:res.status(200)設(shè)置請(qǐng)求頭:res.set(‘a(chǎn)sas’,‘a(chǎn)aa’)設(shè)置響應(yīng)內(nèi)容: res.send(‘你好’)連貫操作:res.status(200).set(‘hahaha~’, ‘hhh’).send(‘你好 express’);
代碼示例如下:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
// //原生響應(yīng)也兼容
// res.statusCode = 200;
// res.statusMessage = 'asasa';
// res.setHeader('hahha', 'hhh');
// res.write('hello world!');
// res.end('res content');
// express設(shè)置狀態(tài)碼
// res.status(200);
// // express設(shè)置請(qǐng)求頭
// res.setset('hahaha~', 'hhh');
// // express響應(yīng)內(nèi)容 做了封裝 中文不亂碼
// res.send('你好');
// 連貫操作
res.status(200).set('hahaha~', 'hhh').send('你好 express');
})
app.listen(3000, () => {
console.log('server started on port 3000');
console.log('http://localhost:3000');
});
其它響應(yīng)設(shè)置
設(shè)置重定向:res.redirect(‘http://www.baidu.com’)下載響應(yīng):res.download(‘路徑’)響應(yīng)json: res.json({內(nèi)容)響應(yīng)文件內(nèi)容:res.sendFile(__dirname+‘/home.html’)
// 其它響應(yīng)
app.get('/other', (req, res) => {
//1-設(shè)置重定向
// res.redirect('http://www.baidu.com');
// 2-下載響應(yīng)
// res.download(__dirname + '/singers.json');
// 3-響應(yīng)json
// res.json({
// "singer_name": "林俊杰",
// "other_name": " JJ Lin",
// "id": 2
// });
//4-響應(yīng)文件內(nèi)容
res.sendFile(__dirname + '/test.html');
})
中間件
中間件介紹
本質(zhì)是一個(gè)回調(diào)函數(shù)可以像回調(diào)喊出一樣訪問 請(qǐng)求對(duì)象,響應(yīng)對(duì)象
中間件作用
中間件作用就是使用函數(shù)封裝公共操作,簡(jiǎn)化代碼
中間件類型
全局中間件路由中間件
全局中間價(jià)
每一個(gè)請(qǐng)求到達(dá)服務(wù)端之后都會(huì)執(zhí)行全局中間件代碼
代碼示例:middleware.js
// 認(rèn)識(shí)中間件
/** 需求
* 追加日志記錄,寫入log.txt文件
*/
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
// 全局中間件
// 定義
function recordMiddleWare(req, res, next) {
// 判斷是否有文件 沒有就創(chuàng)建
const filePath = path.resolve(__dirname, './log.txt');
// 判斷文件是否存在,如果不存在就創(chuàng)建一個(gè)空文件
if (!fs.existsSync(filePath)) {
fs.writeFileSync(filePath, '');
}
// 獲取url和ip地址
const {url, ip} = req;
// 每個(gè)請(qǐng)求過來的路由信息都保存到日志記錄文件
fs.appendFileSync(path.resolve(__dirname, `./log.txt`), `${url} ${ip}\r\n`);
// 調(diào)用next
next();
}
// 調(diào)用中間件函數(shù)
app.use(recordMiddleWare);
app.get('/login', (req, res) => {
res.send('login success!');
})
app.listen(3000, () => {
console.log('server started at port 3000');
console.log('http://localhost:3000');
})
路由中間件實(shí)踐
運(yùn)行點(diǎn)擊測(cè)試1運(yùn)行點(diǎn)擊測(cè)試2運(yùn)行點(diǎn)擊測(cè)試3
代碼示例:middleware_pratice.js
// 中間件實(shí)踐
/** 需求
* 針對(duì)/admin /setting的請(qǐng)求,要求URL攜帶code=521參數(shù),如未攜帶提示【暗號(hào)錯(cuò)誤】
*/
const express = require('express');
const app = express();
// 定義中間件
function checkCodeMiddleWare(req, res, next) {
// 獲取code
const {code} = req.query;
if (Number(code) === 521) {
next();
} else {
next("【暗號(hào)錯(cuò)誤】");
}
}
//調(diào)用中間件
app.get('/admin', checkCodeMiddleWare, (req, res) => {
res.send('admin success!');
})
//調(diào)用中間件
app.get('/setting', checkCodeMiddleWare, (req, res) => {
res.send('setting success!');
})
app.get('/registry', (req, res) => {
res.send('registry success!');
})
app.get('*', (req, res) => {
res.send('
404 Not Found
');})
app.listen(3000, () => {
console.log('server started at port 3000');
console.log('http://localhost:3000');
})
靜態(tài)資源中間件
根目錄下新建public文件夾=》新建index.html文件+新建index.css文件代碼如下:
//靜態(tài)資源中間件請(qǐng)求
app.use(express.static(__dirname + '/public'));
運(yùn)行代碼 staticMiddleware.js,下面路徑express/staticMiddleware.js為自己運(yùn)行的文件路徑
node express/staticMiddleware.js
驗(yàn)證
默認(rèn)打開index.html可直接查看css文件
完整代碼示例:
// 靜態(tài)資源中間件
const express = require('express');
const app = express();
//靜態(tài)資源中間件請(qǐng)求
app.use(express.static(__dirname + '/public'));
// 監(jiān)聽端口 啟動(dòng)服務(wù)
app.listen(3000, () => {
console.log("Server running on port 3000");
console.log('http://localhost:3000');
})
靜態(tài)資源中間件注意事項(xiàng)
index.html為默認(rèn)打開的資源靜態(tài)文件與路由規(guī)則app.get(‘/’,()=>{})同時(shí)匹配,誰先匹配誰就響應(yīng),看代碼順序路由響應(yīng)動(dòng)態(tài)資源,靜態(tài)資源中間件響應(yīng)靜態(tài)資源
獲取請(qǐng)求體數(shù)據(jù)body-parser
安裝
npm i body-parser
獲取中間件函數(shù)
處理queryString格式的請(qǐng)求體:const urlParser = bodyParser.urlencoded({extended: false});處理json格式的請(qǐng)求體:const jsonParser = bodyParser.json();
// 獲取中間件函數(shù)
//處理queryString格式的請(qǐng)求體
const urlParser = bodyParser.urlencoded({extended: false});
//處理json格式的請(qǐng)求體
const jsonParser = bodyParser.json();
使用中間件
//獲取請(qǐng)求體數(shù)據(jù)
app.post('/login', urlParser, (req, res) => {
// 獲取請(qǐng)求體數(shù)據(jù)
console.log(req.body);
res.send('用戶名:' + req.body.username + '
密碼:' + req.body.password);
})
完整代碼示例:bodyParser.js
// body-parse獲取請(qǐng)求體
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
// 獲取中間件函數(shù)
//處理queryString格式的請(qǐng)求體
const urlParser = bodyParser.urlencoded({extended: false});
//處理json格式的請(qǐng)求體
const jsonParser = bodyParser.json();
//響應(yīng)login頁面
app.get('/login', urlParser, (req, res) => {
res.sendFile(__dirname + '/login.html');
})
//獲取請(qǐng)求體數(shù)據(jù)
app.post('/login', urlParser, (req, res) => {
// 獲取請(qǐng)求體數(shù)據(jù)
console.log(req.body);
res.send('用戶名:' + req.body.username + '
密碼:' + req.body.password);
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
})
防盜鏈
介紹
比如有的圖片,直接復(fù)制地址顯示到img是拿不到的,說明這個(gè)網(wǎng)站做了防盜鏈處理。判斷源是請(qǐng)求頭里的referer參數(shù)會(huì)攜帶當(dāng)前域名和協(xié)議及其端口進(jìn)行請(qǐng)求。
實(shí)踐
完整代碼示例:
referer.js
const express = require('express');
const app = express();
// 定義全局防盜鏈中間件 判斷請(qǐng)求頭referer
app.use((req, res, next) => {
const referer = req.get('referer');
if (referer) {
// 實(shí)例化
const url = new URL(referer);
const hostname = url.hostname;
console.log(hostname);
if (hostname !== '127.0.0.1') {
res.status(404).send('
404 Not Found
');return;
}
}
next();
})
// 讀取靜態(tài)資源
app.use(express.static(__dirname + '/public'));
app.listen(3000, () => {
console.log('Express server listening on port 3000');
console.log('http://localhost:3000');
})
public=>index.html
測(cè)試??!
路由模塊化(***)
路由功能代碼進(jìn)行拆分
新建文件夾routes新建homeRouter.js創(chuàng)建單獨(dú)的路由規(guī)則
routermodule.js 代碼示例:
const express = require("express");
const userRouter = require(__dirname + "/routes/userRouter.js");
const adminRouter = require(__dirname + "/routes/adminRouter.js");
const app = express();
app.use(userRouter);
app.use(adminRouter);
app.all("*", function (req, res) {
res.send('404 Not Found');
})
app.listen(3000, () => {
console.log("server started");
console.log('http://localhost:3000');
})
userRouter.js
// user routes
const express = require('express');
const router = express.Router();
router.get('/login', (req, res) => {
res.send('login登錄');
})
router.get('/registry', (req, res) => {
res.send('registry注冊(cè)');
})
module.exports = router;
adminRouter.js
// admin routes
const express = require('express');
const router = express.Router();
router.get('/setting', (req, res) => {
res.send('設(shè)置setting');
})
router.get('/modify', (req, res) => {
res.send('修改setting');
})
module.exports = router;
模版引擎
簡(jiǎn)單介紹
模版引擎是分離用戶界面和業(yè)務(wù)數(shù)據(jù)的一種技術(shù)
ejs
分離HTML和JS的,ejs是一個(gè)高效的JavaScript模版引擎。主要了解ejs,現(xiàn)在不多用了。
安裝
npm i ejs
導(dǎo)入ejs
const ejs = require('ejs');
使用ejs渲染
代碼示例:ejs.js
// ejs初體驗(yàn)
const express = require('express');
const ejs = require('ejs');
const fs = require('fs');
const path = require('path');
const app = express();
// 讀取靜態(tài)資源
app.use(express.static(path.join(__dirname, './public')));
const china = '中國(guó)';
// 讀取html文件
const htmlData = fs.readFileSync(__dirname + '/public/index.html','utf-8').toString();
//使用ejs渲染
const result = ejs.render(htmlData, {china: china});
console.log(result);
代碼示例:index.html
<%= china %>
測(cè)試!!
讀出來了嗎?
<%= china %>
ejs列表渲染
代碼如下:ejs_xiyou.js
// ejs列表渲染
/** 需求
* 渲染ul li 西游數(shù)組
*/
const ejs = require('ejs');
const fs = require('fs');
const xiyou = ['唐僧', '孫悟空', '沙僧', '豬八戒'];
const htmlData = fs.readFileSync(__dirname + '/ejs_xiyou.html').toString()
const result = ejs.render(htmlData, {xiyou: xiyou});
console.log(result);
代碼如下:ejs_xiyou.html
- <%= item %>
<% xiyou.forEach(item=>{ %>
<% }) %>
ejs條件渲染
js如上html如下 代碼示例:
<% if(isLogin){ %>
登錄成功
<% }else{ %>
登錄失敗
<% } %>
express中使用ejs
設(shè)置模板引擎
app.set('view engine', 'ejs');
設(shè)置模板文件存放位置 新建view文件夾=》views新建.ejs文件,比如home.ejs
app.set('views',path.resolve(__dirname,'./views'))
render響應(yīng)
res.render('home',{title})
創(chuàng)建模版文件 其實(shí)就是.ejs文件,但其實(shí)就是類html文件,主要得含有如下代碼:
<%= title %>
完整代碼示例:express_ejs.js
const express = require("express");
const ejs = require("ejs");
const path = require("path");
const app = express();
// 1-設(shè)置模版引擎
app.set("view engine", "ejs");
// 2-設(shè)置模版文件存放位置
app.set("views", path.resolve(__dirname, "./views"));
app.get('/home', (req, res) => {
const title = 'Home頁面';
// 3-render響應(yīng)
res.render("home", {title});
// 創(chuàng)建模版文件 home.ejs
})
app.all('*', (req, res) => {
res.send('404 Not Found');
})
app.listen(3000, () => {
console.log("Server is running on port 3000");
console.log('http://localhost:3000');
});
完整代碼:views=>home.ejs
測(cè)試:
<%= title %>
express-generator工具
通過應(yīng)用生成器express-generator快速創(chuàng)建一個(gè)應(yīng)用骨架
安裝
npx命令來運(yùn)行(包含Node.js8.2.0及更高的版本中)
npx express-generator
npm方式
npm i -g express-generator
創(chuàng)建文件夾
語法 express -e <文件夾名稱>
express -e generator
查看相關(guān)命令
express -h
查看文件上傳報(bào)文
代碼示例 portrait.js
const express = require('express');
const path = require('path');
const app = express();
//設(shè)置模板引擎
app.set('view engine', 'ejs');
//設(shè)置模板引擎存放文件位置
app.set('views', path.resolve(__dirname, './views'));
// render響應(yīng)
app.get('/portrait', (req, res) => {
res.render('portrait');
})
app.post('/portrait', (req, res) => {
console.log(req);
res.send('成功!');
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
});
完整代碼portrait.ejs
處理文件上傳
借助庫formidable 使用參考注意:Commonjs 使用require引入需要安裝V2版本的,V3的只能使用import 引入創(chuàng)建public文件夾=》images文件夾
代碼示例:
const express = require('express');
const path = require('path');
const formidable = require('formidable').formidable;
const app = express();
//設(shè)置模板引擎
app.set('view engine', 'ejs');
//設(shè)置模板引擎存放文件位置
app.set('views', path.resolve(__dirname, './views'));
// render響應(yīng)
app.get('/portrait', (req, res) => {
res.render('portrait');
})
// 響應(yīng)靜態(tài)資源——方便訪問上傳的圖片
app.use(express.static(path.resolve(__dirname, './public')));
app.post('/portrait', (req, res) => {
const form = formidable({
multiple: true,
// 設(shè)置上傳文件的保存目錄
uploadDir: path.join(__dirname, './public/images'),
// 保持文件后綴
keepExtensions: true
})
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
// 存放非文件的字段
// console.log(fields);
// 存放文件
// console.log(files);
// 服務(wù)器保存存放的照片的訪問url
const url = '/images/' + files.portrait.newFilename;
res.send(url);
});
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
});
mongoDB
介紹
基于分布式文件存儲(chǔ)的數(shù)據(jù)庫,官方網(wǎng)址
相比于純文件管理數(shù)據(jù),數(shù)據(jù)庫管理數(shù)據(jù)優(yōu)點(diǎn):
速度更快擴(kuò)展性更強(qiáng)安全性更強(qiáng)
核心概念
數(shù)據(jù)庫:又稱數(shù)據(jù)倉(cāng)庫,可存放很多集合集合:類似于JS中的數(shù)據(jù),在集合中可以存放很多文檔文檔:數(shù)據(jù)庫中的最小單位,類似JS中的對(duì)象
下載安裝與啟動(dòng)
下載地址 這邊記錄下自己的mac安裝教程,可根據(jù)直接的電腦系統(tǒng)去搜搜安裝
參考mac安裝mongoDB數(shù)據(jù)庫
具體步驟:
進(jìn)入MongoDB官網(wǎng)進(jìn)行下載下載完畢并且解壓,重新命名為 【mongodb】文件夾打開訪達(dá) 按住快捷鍵command+shift+g 前往/usr/local路徑將解壓并命名好的【mongodb】文件夾拖入到這個(gè)路徑下配置環(huán)境變量,在根目錄輸入open -e .zshrc打開.zshrc文件夾。(注意:我的終端是zsh,如果你們的終端是bash的話應(yīng)該輸入open .bash_profile)在里面添加一下代碼
export PATH=${PATH}:/usr/local/mongodb/bin
保存好了文件后,需要執(zhí)行改文件,在根目錄輸入 source .zshrc 來進(jìn)行執(zhí)行。(注意:我的終端是zsh,如果你們的終端是bash的話應(yīng)該輸入source .bash_profile)在此執(zhí)行一下命令(確保是在根目錄 不確定就執(zhí)行 cd ~)
mongod --version
安裝mongodb成功了后,那存的數(shù)據(jù)和日志記錄放哪呢。這就需要建立data和log文件夾了。進(jìn)入到mongodb文件夾的目錄下
進(jìn)行mongodb文件夾下
cd /usr/local/mongodb
創(chuàng)建
mkdir data log
給這data文件夾賦予讀寫權(quán)限,輸入電腦開機(jī)密碼,密碼輸入的時(shí)候看不見。
sudo chown [你的用戶名] /usr/local/mongodb/data
給這log文件夾賦予讀寫權(quán)限,輸入電腦開機(jī)密碼,密碼輸入的時(shí)候看不見。
sudo chown [你的用戶名] /usr/local/mongodb/log
在mongondb路徑下啟動(dòng)mongoDB:mongod --fork --dbpath data --logpath log/mongo.log --logappend 這句命令,看到child process started successfully, parent exiting這句話就成功啟動(dòng)服務(wù)了
mongod --fork --dbpath data --logpath log/mongo.log --logappend
使用mongo指令 瀏覽器進(jìn)入http://127.0.0.1:27017/ 關(guān)閉數(shù)據(jù)庫服務(wù) (直接關(guān)閉)針對(duì)于(mac zsh)
sudo pkill -f mongod
再次訪問上面網(wǎng)址就會(huì)失敗
mac zsh配置啟動(dòng)腳本
創(chuàng)建一個(gè)啟動(dòng)腳本文件,以確保命令在正確的目錄中運(yùn)行:
創(chuàng)建腳本文件:
touch start_mongo.sh
編輯腳本文件:
nano start_mongo.sh
添加以下內(nèi)容:
#!/bin/zsh
cd /usr/local/mongodb
mongod --fork --dbpath data --logpath log/mongo.log --logappend
保存并退出: 保存文件并退出編輯器(按Ctrl+X退出,按Y保存,回車enter退出)。
PS:同理建立了關(guān)閉mongods腳本。 命令為:
sudo pkill -f mongod
賦予執(zhí)行權(quán)限:
chmod +x start_mongo.sh
運(yùn)行腳本: 現(xiàn)在你可以運(yùn)行腳本來啟動(dòng)MongoDB:
./start_mongo.sh
mac下載可視化工具Robomongo(studio3T)
下載地址參考可視化工具Robomongo(studio3T)安裝使用
文檔命令
插入文檔
語法:db.集合名.insert(文檔對(duì)象)
db.user.insert({username:'ll',age:18})
查詢文檔
語法:db.集合名.find(查詢條件)
db.user.find({age:20})
更新文檔
語法:db.集合名.update(查詢條件,新的文檔)
db.user.find({name:'張三'},{$set:{age:20}})
刪除文檔
語法:db.集合名.remove(查詢條件)
db.user.remove({name:'張三'})
mongoose
連接數(shù)據(jù)庫
代碼及說明如下:
// mongoose使用 前提得啟動(dòng)mongoose
// 1-安裝依賴
// 2-引入依賴
const mongoose = require('mongoose');
// 3-連接mongodb服務(wù)
mongoose.connect('mongodb://127.0.0.1:27017/user');
// 補(bǔ)充說明:1-設(shè)置strictQuery為true
mongoose.set('strictQuery', true);
// 設(shè)置回調(diào)
// 連接成功的回調(diào) 補(bǔ)充說明:2-once:事件回調(diào)函數(shù)只執(zhí)行一次
mongoose.connection.on('open', () => {
console.log('連接成功!');
})
// 連接錯(cuò)誤的回調(diào)
mongoose.connection.on('error', (err) => {
console.log('連接錯(cuò)誤:')
console.error(err);
})
// 連接關(guān)閉的回調(diào)
mongoose.connection.on('close', () => {
console.log('連接關(guān)閉');
})
// 關(guān)閉連接
setTimeout(function () {
console.log('連接關(guān)閉');
mongoose.disconnect();
}, 2000)
…mongoose大致學(xué)到這里,需要的在看文檔好了…
會(huì)話控制
介紹
所謂會(huì)話控制是對(duì)會(huì)話進(jìn)行控制。 因?yàn)镠TTP是一個(gè)無狀態(tài)的協(xié)議,它沒有辦法區(qū)分多次的請(qǐng)求是否來自同一客戶端,無法區(qū)分用戶,而產(chǎn)品中又大量存在這樣的需求,所以我們需要通過會(huì)話控制解決該問題。
常見的會(huì)話控制方式:
CookieSessionToken
Cookie
cookie是HTTP服務(wù)器發(fā)送到用戶瀏覽器并保存在本地的一小塊數(shù)據(jù)
cookie是保存在瀏覽器的一小塊數(shù)據(jù)cookie是按照域名劃分保存的
特點(diǎn):
瀏覽器向服務(wù)器發(fā)送請(qǐng)求時(shí),會(huì)自動(dòng)將當(dāng)前域名可用的cookie設(shè)置在請(qǐng)求頭中,然后傳遞給服務(wù)器。請(qǐng)求頭的名字也叫cookie 所以將cookie理解為一個(gè)http的請(qǐng)求頭也是可以的
瀏覽器Cookie
禁用cookie
這個(gè)操作一般不做
網(wǎng)站——隱私設(shè)置和安全性設(shè)置——常規(guī)設(shè)置——阻止所有cookie
刪除cookie
網(wǎng)站——隱私設(shè)置和安全性設(shè)置——清除相應(yīng)網(wǎng)站數(shù)據(jù)
查看cookie
edge瀏覽器查看——輸入cookie查詢——cookie和網(wǎng)站數(shù)據(jù)——點(diǎn)擊下拉查看谷歌瀏覽器查看——網(wǎng)站鏈接旁的左上方小鎖——cookie和網(wǎng)站數(shù)據(jù)——點(diǎn)擊查看
express Cookie
設(shè)置cookie
eg:res.cookie(‘name’,‘lhm’,{})
const express = require('express');
const app = express();
app.get('/set-cookie',(req,res)=>{
res.cookie('name','lhm');//會(huì)在瀏覽器關(guān)閉的時(shí)候,銷毀
res.cookie('name','lhm',{maxAge:60 * 1000}); //maxAge最大存活時(shí)間 單位毫秒 但是瀏覽器中存的是秒s
res.send('home');
})
刪除cookie
eg:res.clearCookie(‘name’)
const express = require('express');
const app = express();
app.get('/remove-cookie',(req,res)=>{
res.clearCookie('name');
res.send('remove');
})
讀取cookie
工具庫cookie-parse,使用這個(gè)為一個(gè)cookie解析中間件
安裝依賴
npm i cookie-parse
引入使用
const express = require('express');
const cookieParse = require('cookie-parse');
const app = express();
app.use(cookieParse());
獲取cookie值
req.cookies獲取到cookie值
app.get('/get-cookie',(req,res)=>{
console.log(req.cookies);
console.log(res.cookies.name);
})
session
保存到服務(wù)器的一塊兒數(shù)據(jù),保存當(dāng)前訪問的用戶的相關(guān)信息
作用:
實(shí)現(xiàn)會(huì)話控制,可以識(shí)別用戶的身份,快速獲取當(dāng)前用戶的相關(guān)信息
運(yùn)行流程:
填寫賬號(hào)和密碼校驗(yàn)身份,校驗(yàn)填入通過后創(chuàng)建session信息,然后通過session_id的值通過響應(yīng)頭返回給瀏覽器有了cookie,下載發(fā)送請(qǐng)求會(huì)自動(dòng)攜帶cookie,服務(wù)器通過cookie和session_id的值確定用戶的身份
session與cookie區(qū)別
存在位置不同。cookie存在瀏覽器,session 服務(wù)端安全性。cookie明文存在客戶端,session是存在服務(wù)器,安全性相對(duì)較好網(wǎng)絡(luò)傳輸量。 cookie設(shè)置內(nèi)容過多會(huì)增加保溫體積,影響傳輸效率。session數(shù)據(jù)存儲(chǔ)在服務(wù)器,只是通過cookie傳遞id,所以不影響傳輸效率存儲(chǔ)限制。cookie保存的數(shù)據(jù)不超過4k 且單個(gè)域名下的存儲(chǔ)數(shù)量有限。session數(shù)據(jù)存儲(chǔ)在服務(wù)器,沒有限制。
視頻的基礎(chǔ)知識(shí)大致學(xué)到這里,下面似乎涉及用處小,需要的時(shí)候還有機(jī)會(huì)的話再更新吧…
完結(jié)撒花~~~
柚子快報(bào)激活碼778899分享:vim node.js學(xué)習(xí)
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。