一、Node.js是什么
Node.js? is a JavaScript runtime built on Chrome's V8 JavaScript engine.
1政敢、特性
Node.js 可以解析JS代碼(沒有瀏覽器安全級別的限制)提供很多系統(tǒng)級別的API由缆,如:
- 文件的讀寫 (File System)
- 進程的管理 (Process)
- 網(wǎng)絡通信 (HTTP/HTTPS)
- ……
2匾七、舉例
2.1 瀏覽器安全級別的限制
Ajax測試
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>browser-safe-sandbox</title>
</head>
<body>
<div>browser-safe-sandbox</div>
<script>
const xhr = new XMLHttpRequest()
xhr.open('get', 'https://m.maoyan.com/ajax/moreClassicList?sortId=1&showType=3&limit=10&offset=30&optimus_uuid=A5518FF0AFEC11EAAB158D7AB0D05BBBD74C9789D9F649898982E6542C7DD479&optimus_risk_level=71&optimus_code=10', false)
xhr.send()
</script>
</body>
</html>
瀏覽器預覽
browser-sync start --server --files **/* --directory
2.2 文件的讀寫 (File System)
const fs = require('fs')
fs.readFile('./ajax.png', 'utf-8', (err, content) => {
console.log(content)
})
2.3 進程的管理(Process)
function main(argv) {
console.log(argv)
}
main(process.argv.slice(2))
運行
node 2.3-process.js argv1 argv2
2.4 網(wǎng)絡通信(HTTP/HTTPS)
const http = require("http")
http.createServer((req,res) => {
res.writeHead(200, {
"content-type": "text/plain"
})
res.write("hello nodejs")
res.end()
}).listen(3000)
二卒蘸、Node 相關(guān)工具
1填抬、NVM: Node Version Manager
1.1 Mac 安裝 nvm
https://github.com/nvm-sh/nvm/blob/master/README.md
1.2 Windows 安裝 nvm
nvm-windows
nodist
2、NPM: Node Package Manager
2.1 全局安裝package
$ npm install forever --global (-g)
$ forever
$ npm uninstall forever --global
$ forever
全局安裝包的目錄
-
Mac
/Users/felix/.nvm/versions/node/nvm各個版本/bin/
-
Windows
C:\Users\你的用戶名\AppData\Roaming\npm\node_modules
2.2 本地安裝package
$ cd ~/desktop
$ mkdir gp-project
$ cd gp-project
$ npm install underscore
$ npm list (ls)
2.3 package.json初始化
$ pwd
$ npm init -y
$ ls
$ cat package.json
2.4 使用package.json
$ npm install underscore --save
$ cat package.json
$ npm install lodash --save-dev
$ cat package.json
$ rm -rf node_modules
$ ls
$ npm install
$ npm uninstall underscore --save
$ npm list | grep underscore
$ cat package.json
2.5 安裝指定版本的包
$ pwd
$ npm list
$ npm info underscore
$ npm view underscore versions
$ npm install underscore@1.8.0
$ npm list
$ npm uninstall underscore
$ npm list
2.6 更新本地安裝的包
$ npm info underscore
$ npm view underscore versions
$ npm install underscore@1.4.4 --save-dev
$ npm list | grep gulp
$ npm outdated //~2.0.0表示patch, ^2.0.0表示minor * 表示xx最新版本
$ npm list | grep gulp
$ npm update
2.7 清除緩存
npm cache clean --force
2.8 上傳自己的包
2.8.1 編寫模塊
保存為index.js
exports.sayHello = function(){
return 'Hello World';
}
2.8.2 初始化包描述文件
$ npm init package.json
{
"name": "gp19-npm",
"version": "1.0.1",
"description": "gp19 self module",
"main": "index.js",
"scripts": {
"test": "make test"
},
"repository": {
"type": "Git",
"url": "git+https://github.com/lurongtao/gp19-npm.git"
},
"keywords": [
"demo"
],
"author": "Felixlu",
"license": "ISC",
"bugs": {
"url": "https://github.com/lurongtao/gp19-npm/issues"
},
"homepage": "https://github.com/lurongtao/gp19-npm#readme",
}
2.8.3 注冊npm倉庫賬號
https://www.npmjs.com 上面的賬號
felix_lurt/qqmko09ijn
$ npm adduser
2.8.4 上傳包
$ npm publish
坑:403 Forbidden
查看npm源:npm config get registry
切換npm源方法一:npm config set registry http://registry.npmjs.org
切換npm源方法二:nrm use npm
2.8.5 安裝包
$ npm install gp19-npm
2.8.6 卸載包
查看當前項目引用了哪些包 :
npm ls
卸載包:
npm unpublish --force
2.8.7 使用引入包
var hello = require('gp19-npm')
hello.sayHello()
2.9 npm 腳本
Node 開發(fā)離不開 npm辆童,而腳本功能是 npm 最強大宜咒、最常用的功能之一。
一把鉴、什么是 npm 腳本故黑?
npm 允許在 package.json 文件里面,使用 scripts 字段定義腳本命令庭砍。
{
// ...
"scripts": {
"build": "node build.js"
}
}
二场晶、執(zhí)行順序
如果 npm 腳本里面需要執(zhí)行多個任務,那么需要明確它們的執(zhí)行順序怠缸。
script1.js
var x = 0
console.log(x)
script2.js
var y = 0
console.log(y)
"scripts": {
"script1": "node script1.js",
"script2": "node script2.js"
}
如果是并行執(zhí)行(即同時的平行執(zhí)行)诗轻,可以使用 &
符號。
$ npm run script1 & npm run script2
如果是繼發(fā)執(zhí)行(即只有前一個任務成功揭北,才執(zhí)行下一個任務)扳炬,可以使用 &&
符號。
$ npm run script1 && npm run script2
三罐呼、簡寫形式
常用的 npm 腳本簡寫形式鞠柄。
npm start 是 npm run start
四、變量
npm 腳本有一個非常強大的功能嫉柴,就是可以使用 npm 的內(nèi)部變量厌杜。
首先,通過 npm_package_
前綴,npm 腳本可以拿到 package.json 里面的字段夯尽。比如瞧壮,下面是一個 package.json。
注意:一定要在 npm 腳本中運行(如:npm run view)才可以匙握,直接在命令行中運行JS(如:node view.js)是拿不到值的
{
"name": "foo",
"version": "1.2.5",
"scripts": {
"view": "node view.js"
}
}
那么咆槽,變量 npm_package_name 返回 foo,變量 npm_package_version 返回 1.2.5圈纺。
// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5
上面代碼中秦忿,我們通過環(huán)境變量 process.env 對象,拿到 package.json 的字段值蛾娶。如果是 Bash 腳本灯谣,可以用npm_package_version 取到這兩個值。
npmpackage前綴也支持嵌套的package.json字段蛔琅。
"repository": {
"type": "git",
"url": "xxx"
},
scripts: {
"view": "echo $npm_package_repository_type"
}
上面代碼中胎许,repository 字段的 type 屬性,可以通過 npm_package_repository_type 取到罗售。
下面是另外一個例子辜窑。
"scripts": {
"install": "foo.js"
}
上面代碼中,npm_package_scripts_install 變量的值等于 foo.js寨躁。
然后穆碎,npm 腳本還可以通過 npmconfig 前綴,拿到 npm 的配置變量朽缎,即 npm config get xxx 命令返回的值惨远。比如,當前模塊的發(fā)行標簽话肖,可以通過 npm_config_tag 取到北秽。
"view": "echo $npm_config_tag",
注意,package.json 里面的 config 對象最筒,可以被環(huán)境變量覆蓋贺氓。
{
"name" : "foo",
"config" : { "port" : "8080" },
"scripts" : { "start" : "node server.js" }
}
上面代碼中,npm_package_config_port 變量返回的是 8080床蜘。這個值可以用下面的方法覆蓋辙培。
$ npm config set foo:port 80
最后,env命令可以列出所有環(huán)境變量邢锯。
"env": "env"
2.10 npm 安裝 git 上發(fā)布的包
# 這樣適合安裝公司內(nèi)部的git服務器上的項目
npm install git+https://git@github.com:lurongtao/gp-project.git
# 或者以ssh的方式
npm install git+ssh://git@github.com:lurongtao/gp-project.git
2.11 cross-env 使用
2.11.1 cross-env是什么
運行跨平臺設置和使用環(huán)境變量的腳本
2.11.2 出現(xiàn)原因
當您使用 NODE_ENV=production, 來設置環(huán)境變量時扬蕊,大多數(shù) Windows 命令提示將會阻塞(報錯)。(異常是Windows上的Bash丹擎,它使用本機Bash尾抑。)換言之歇父,Windows 不支持 NODE_ENV=production 的設置方式。
2.11.3 解決
cross-env 使得您可以使用單個命令再愈,而不必擔心為平臺正確設置或使用環(huán)境變量榜苫。這個迷你的包(cross-env)能夠提供一個設置環(huán)境變量的 scripts,讓你能夠以 Unix 方式設置環(huán)境變量翎冲,然后在 Windows 上也能兼容運行垂睬。
2.11.4 安裝
npm install --save-dev cross-env
2.11.5 使用
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
}
NODE_ENV環(huán)境變量將由 cross-env 設置 打印 process.env.NODE_ENV === 'production'
3、NRM: npm registry manager
3.1 手工切換源
3.1.1 查看當前源
npm config get registry
3.1.2 切換淘寶源
npm config set registry https://registry.npm.taobao.org
3.2 NRM 管理源
NRM (npm registry manager)是npm的鏡像源管理工具抗悍,有時候國外資源太慢驹饺,使用這個就可以快速地在 npm 源間切換。
3.2.1 安裝 nrm
在命令行執(zhí)行命令缴渊,npm install -g nrm逻淌,全局安裝nrm。
3.2.2 使用 nrm
執(zhí)行命令 nrm ls 查看可選的源疟暖。 其中,帶*的是當前使用的源田柔,上面的輸出表明當前源是官方源俐巴。
3.2.3 切換 nrm
如果要切換到taobao源,執(zhí)行命令nrm use taobao硬爆。
3.2.4 測試速度
你還可以通過 nrm test 測試相應源的響應時間欣舵。
nrm test
4、NPX: npm package extention
npm 從5.2版開始缀磕,增加了 npx 命令缘圈。它有很多用處,本文介紹該命令的主要使用場景袜蚕。
Node 自帶 npm 模塊糟把,所以可以直接使用 npx 命令。萬一不能用牲剃,就要手動安裝一下遣疯。
$ npm install -g npx
4.1 調(diào)用項目安裝的模塊
npx 想要解決的主要問題,就是調(diào)用項目內(nèi)部安裝的模塊凿傅。比如缠犀,項目內(nèi)部安裝了Mocha。
$ npm install -D mocha
一般來說聪舒,調(diào)用 Mocha 辨液,只能在項目腳本和 package.json 的scripts字段里面,如果想在命令行下調(diào)用箱残,必須像下面這樣滔迈。
# 項目的根目錄下執(zhí)行
$ node-modules/.bin/mocha --version
npx 就是想解決這個問題,讓項目內(nèi)部安裝的模塊用起來更方便,只要像下面這樣調(diào)用就行了亡鼠。
$ npx mocha --version
npx 的原理很簡單赏殃,就是運行的時候,會到node_modules/.bin路徑和環(huán)境變量$PATH里面间涵,檢查命令是否存在仁热。
由于 npx 會檢查環(huán)境變量$PATH,所以系統(tǒng)命令也可以調(diào)用勾哩。
# 等同于 ls
$ npx ls
注意抗蠢,Bash 內(nèi)置的命令不在$PATH里面,所以不能用思劳。比如迅矛,cd是 Bash 命令,因此就不能用npx cd潜叛。
4.2 避免全局安裝模塊
除了調(diào)用項目內(nèi)部模塊秽褒,npx 還能避免全局安裝的模塊。比如威兜,create-react-app 這個模塊是全局安裝销斟,npx 可以運行它,而且不進行全局安裝椒舵。
$ npx create-react-app my-react-app
上面代碼運行時蚂踊,npx 將 create-react-app 下載到一個臨時目錄,使用以后再刪除笔宿。所以犁钟,以后再次執(zhí)行上面的命令,會重新下載 create-react-app泼橘。
注意涝动,只要 npx 后面的模塊無法在本地發(fā)現(xiàn),就會下載同名模塊侥加。比如捧存,本地沒有安裝http-server模塊,下面的命令會自動下載該模塊担败,在當前目錄啟動一個 Web 服務昔穴。
$ npx http-server
4.3 --no-install 參數(shù)和 --ignore-existing 參數(shù)
如果想讓 npx 強制使用本地模塊,不下載遠程模塊提前,可以使用--no-install參數(shù)吗货。如果本地不存在該模塊,就會報錯狈网。
$ npx --no-install http-server
反過來宙搬,如果忽略本地的同名模塊笨腥,強制安裝使用遠程模塊,可以使用--ignore-existing參數(shù)勇垛。比如脖母,本地已經(jīng)安裝了http-server,但還是想使用遠程模塊闲孤,就用這個參數(shù)谆级。
$ npx --ignore-existing http-server
三、模塊/包 與 CommonJS
1讼积、模塊/包分類
Node.js 有三類模塊肥照,即內(nèi)置的模塊、第三方的模塊勤众、自定義的模塊舆绎。
1.1 內(nèi)置的模塊
Node.js 內(nèi)置模塊又叫核心模塊,Node.js安裝完成可直接使用们颜。如:
const path = require('path')
var extname = path.extname('index.html')
console.log(extname)
1.2 第三方的Node.js模塊
第三方的Node.js模塊指的是為了實現(xiàn)某些功能吕朵,發(fā)布的npmjs.org上的模塊,按照一定的開源協(xié)議供社群使用窥突。如:
npm install chalk
const chalk = require('chalk')
console.log(chalk.blue('Hello world!'))
1.3 自定義的Node.js模塊
自定義的Node.js模塊边锁,也叫文件模塊,是我們自己寫的供自己使用的模塊波岛。同時,這類模塊發(fā)布到npmjs.org上就成了開源的第三方模塊音半。
自定義模塊是在運行時動態(tài)加載则拷,需要完整的路徑分析、文件定位曹鸠、編譯執(zhí)行過程煌茬、速度相比核心模塊稍微慢一些,但是用的非常多彻桃。
1.3.1 模塊定義坛善、接口暴露和引用接口
我們可以把公共的功能 抽離成為一個單獨的 js 文件 作為一個模塊,默認情況下面這個模塊里面的方法或者屬性邻眷,外面是沒法訪問的眠屎。如果要讓外部可以訪問模塊里面的方法或者屬性,就必須在模塊里面通過 exports 或者 module.exports 暴露屬性或者方法肆饶。
m1.js:
const name = 'gp19'
const sayName = () => {
console.log(name)
}
console.log('module 1')
// 接口暴露方法一:
module.exports = {
say: sayName
}
// 接口暴露方法二:
exports.say = sayName
// 錯誤改衩!
exports = {
say: sayName
}
main.js:
const m1 = require('./m1')
m1.say()
1.3.2 模塊的循環(huán)引用
由于 exports 使用方式方式不對,會在兩個不同 js 循環(huán)引用的情況下驯镊,導致其中一個 js 無法獲取另外一個 js 的方法葫督,從而導致執(zhí)行報錯竭鞍。如:
- a.js
exports.done = false
const b = require('./b.js')
console.log('in a, b.done = %j', b.done)
exports.done = true
console.log('a done')
- b.js
console.log('b starting')
exports.done = false
const a = require('./a.js')
console.log('in b, a.done = %j', a.done)
exports.done = true
console.log('b done')
- main.js
console.log('main starting')
const a = require('./a.js')
const b = require('./b.js')
console.log('in main, a.done = %j, b.done = %j', a.done, b.done)
main.js 首先會 load a.js, 此時執(zhí)行到const b = require('./b.js');的時候,程序會轉(zhuǎn)去loadb.js, 在b.js中執(zhí)行到const a = require('./a.js'); 為了防止無限循環(huán)橄镜,將a.jsexports的未完成副本返回到b.js模塊偎快。然后b.js完成加載,并將其導出對象提供給a.js模塊洽胶。
我們知道nodeJs的對每個js文件進行了一層包裝稱為module晒夹,module中有一個屬性exports,當調(diào)用require('a.js')的時候其實返回的是module.exports對象妖异,module.exports初始化為一個{}空的object惋戏,所以在上面的例子中,執(zhí)行到b.js中const a = require('./a.js');時不會load新的a module, 而是將已經(jīng)load但是還未完成的a module的exports屬性返回給b module他膳,所以b.js拿到的是a module的exports對象响逢,即:{done:false}, 雖然在a.js中exports.done被修改成了true,但是由于此時a.js未load完成棕孙,所以在b.js輸出的a module的屬性done為false舔亭,而在main.js中輸出的a module的屬性done為true. Nodejs通過上面這種返回未完成exports對象來解決循環(huán)引用的問題。
四蟀俊、常用內(nèi)置模塊
這里介紹幾個常用的內(nèi)置模塊:url, querystring, http, events, fs, stream, readline, crypto, zlib
1钦铺、url
1.1 parse
url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
const url = require('url')
const urlString = 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
const parsedStr = url.parse(urlString)
console.log(parsedStr)
1.2 format
url.format(urlObject)
const url = require('url')
const urlObject = {
protocol: 'https:',
slashes: true,
auth: null,
host: 'www.baidu.com:443',
port: '443',
hostname: 'www.baidu.com',
hash: '#tag=110',
search: '?id=8&name=mouse',
query: { id: '8', name: 'mouse' },
pathname: '/ad/index.html',
path: '/ad/index.html?id=8&name=mouse',
href: 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
}
const parsedObj = url.format(urlObject)
console.log(parsedObj)
1.3 resolve
url.resolve(from, to)
const url = require('url')
var a = url.resolve('/one/two/three', 'four')
var b = url.resolve('http://example.com/', '/one')
var c = url.resolve('http://example.com/one', '/two')
console.log(a + "," + b + "," + c)
2、querystring
2.1 parse
querystring.parse(str[, sep[, eq[, options]]])
const querystring = require('querystring')
var qs = 'x=3&y=4'
var parsed = querystring.parse(qs)
console.log(parsed)
2.2 stringify
querystring.stringify(obj[, sep[, eq[, options]]])
const querystring = require('querystring')
var qo = {
x: 3,
y: 4
}
var parsed = querystring.stringify(qo)
console.log(parsed)
2.3 escape/unescape
querystring.escape(str)
const querystring = require('querystring')
var str = 'id=3&city=北京&url=https://www.baidu.com'
var escaped = querystring.escape(str)
console.log(escaped)
querystring.unescape(str)
const querystring = require('querystring')
var str = 'id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com'
var unescaped = querystring.unescape(str)
console.log(unescaped)
3肢预、http/https
3.1 get
var http = require('http')
var https = require('https')
// 1矛洞、接口 2、跨域
const server = http.createServer((request, response) => {
var url = request.url.substr(1)
var data = ''
response.writeHeader(200, {
'content-type': 'application/json;charset=utf-8',
'Access-Control-Allow-Origin': '*'
})
https.get(`https://m.lagou.com/listmore.json${url}`, (res) => {
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
response.end(JSON.stringify({
ret: true,
data
}))
})
})
})
server.listen(8080, () => {
console.log('localhost:8080')
})
3.2 post:服務器提交(攻擊)
const https = require('https')
const querystring = require('querystring')
const postData = querystring.stringify({
province: '上海',
city: '上海',
district: '寶山區(qū)',
address: '同濟支路199號智慧七立方3號樓2-4層',
latitude: 43.0,
longitude: 160.0,
message: '求購一條小魚',
contact: '13666666',
type: 'sell',
time: 1571217561
})
const options = {
protocol: 'https:',
hostname: 'ik9hkddr.qcloud.la',
method: 'POST',
port: 443,
path: '/index.php/trade/add_item',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
}
function doPost() {
let data
let req = https.request(options, (res) => {
res.on('data', chunk => data += chunk)
res.on('end', () => {
console.log(data)
})
})
req.write(postData)
req.end()
}
// setInterval(() => {
// doPost()
// }, 1000)
3.3 跨域:jsonp
const http = require('http')
const url = require('url')
const app = http.createServer((req, res) => {
let urlObj = url.parse(req.url, true)
switch (urlObj.pathname) {
case '/api/user':
res.end(`${urlObj.query.cb}({"name": "gp145"})`)
break
default:
res.end('404.')
break
}
})
app.listen(8080, () => {
console.log('localhost:8080')
})
3.4 跨域:CORS
const http = require('http')
const url = require('url')
const querystring = require('querystring')
const app = http.createServer((req, res) => {
let data = ''
let urlObj = url.parse(req.url, true)
res.writeHead(200, {
'content-type': 'application/json;charset=utf-8',
'Access-Control-Allow-Origin': '*'
})
req.on('data', (chunk) => {
data += chunk
})
req.on('end', () => {
responseResult(querystring.parse(data))
})
function responseResult(data) {
switch (urlObj.pathname) {
case '/api/login':
res.end(JSON.stringify({
message: data
}))
break
default:
res.end('404.')
break
}
}
})
app.listen(8080, () => {
console.log('localhost:8080')
})
3.5 跨域:middleware(http-proxy-middware)
const http = require('http')
const proxy = require('http-proxy-middleware')
http.createServer((req, res) => {
let url = req.url
res.writeHead(200, {
'Access-Control-Allow-Origin': '*'
})
if (/^\/api/.test(url)) {
let apiProxy = proxy('/api', {
target: 'https://m.lagou.com',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
})
// http-proy-middleware 在Node.js中使用的方法
apiProxy(req, res)
} else {
switch (url) {
case '/index.html':
res.end('index.html')
break
case '/search.html':
res.end('search.html')
break
default:
res.end('[404]page not found.')
}
}
}).listen(8080)
3.6 爬蟲
const https = require('https')
const http = require('http')
const cheerio = require('cheerio')
http.createServer((request, response) => {
response.writeHead(200, {
'content-type': 'application/json;charset=utf-8'
})
const options = {
protocol: 'https:',
hostname: 'maoyan.com',
port: 443,
path: '/',
method: 'GET'
}
const req = https.request(options, (res) => {
let data = ''
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
filterData(data)
})
})
function filterData(data) {
let $ = cheerio.load(data)
let $movieList = $('.movie-item')
let movies = []
$movieList.each((index, value) => {
movies.push({
title: $(value).find('.movie-title').attr('title'),
score: $(value).find('.movie-score i').text(),
})
})
response.end(JSON.stringify(movies))
}
req.end()
}).listen(9000)
4烫映、Events
const EventEmitter = require('events')
class MyEventEmitter extends EventEmitter {}
const event = new MyEventEmitter()
event.on('play', (movie) => {
console.log(movie)
})
event.emit('play', '我和我的祖國')
event.emit('play', '中國機長')
5沼本、File System
const fs = require('fs')
const fsP = require('fs').promises
// 創(chuàng)建文件夾
fs.mkdir('./logs', (err) => {
console.log('done.')
})
// 文件夾改名
fs.rename('./logs', './log', () => {
console.log('done')
})
// 刪除文件夾
fs.rmdir('./log', () => {
console.log('done.')
})
// 寫內(nèi)容到文件里
fs.writeFile(
'./logs/log1.txt',
'hello',
// 錯誤優(yōu)先的回調(diào)函數(shù)
(err) => {
if (err) {
console.log(err.message)
} else {
console.log('文件創(chuàng)建成功')
}
}
)
// 給文件追加內(nèi)容
fs.appendFile('./logs/log1.txt', '\nworld', () => {
console.log('done.')
})
// 讀取文件內(nèi)容
fs.readFile('./logs/log1.txt', 'utf-8', (err, data) => {
console.log(data)
})
// 刪除文件
fs.unlink('./logs/log1.txt', (err) => {
console.log('done.')
})
// 批量寫文件
for (var i = 0; i < 10; i++) {
fs.writeFile(`./logs/log-${i}.txt`, `log-${i}`, (err) => {
console.log('done.')
})
}
// 讀取文件/目錄信息
fs.readdir('./', (err, data) => {
data.forEach((value, index) => {
fs.stat(`./${value}`, (err, stats) => {
// console.log(value + ':' + stats.size)
console.log(value + ' is ' + (stats.isDirectory() ? 'directory' : 'file'))
})
})
})
// 同步讀取文件
try {
const content = fs.readFileSync('./logs/log-1.txt', 'utf-8')
console.log(content)
console.log(0)
} catch (e) {
console.log(e.message)
}
console.log(1)
// 異步讀取文件:方法一
fs.readFile('./logs/log-0.txt', 'utf-8', (err, content) => {
console.log(content)
console.log(0)
})
console.log(1)
// 異步讀取文件:方法二
fs.readFile('./logs/log-0.txt', 'utf-8').then(result => {
console.log(result)
})
// 異步讀取文件:方法三
function getFile() {
return new Promise((resolve) => {
fs.readFile('./logs/log-0.txt', 'utf-8', (err, data) => {
resolve(data)
})
})
}
;(async () => {
console.log(await getFile())
})()
// 異步讀取文件:方法四
const fsp = fsP.readFile('./logs/log-1.txt', 'utf-8').then((result) => {
console.log(result)
})
console.log(fsP)
// watch 監(jiān)測文件變化
fs.watch('./logs/log-0.txt', () => {
console.log(0)
})
6、Stream
const fs = require('fs')
const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.txt')
writestream.write(readstream)
7锭沟、Zlib
const fs = require('fs')
const zlib = require('zlib')
const gzip = zlib.createGzip()
const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.txt')
readstream
.pipe(gzip)
.pipe(writestream)
writestream.write(readstream)
8抽兆、ReadLine
const readline = require('readline')
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('What do you think of Node.js? ', (answer) => {
// TODO: Log the answer in a database
console.log(`Thank you for your valuable feedback: ${answer}`)
rl.close()
})
9、Crypto
const crypto = require('crypto')
const secret = 'abcdefg'
const hash = crypto.createHmac('sha256', secret)
.update('I love you')
.digest('hex')
console.log(hash)
四族淮、路由
var http = require('http')
var fs = require('fs')
http.createServer( function ( req, res ) {
switch ( req.url ) {
case '/home':
res.write('home')
res.end()
break
case '/mine':
res.write('mine')
res.end()
break
case '/login':
fs.readFile( './static/login.html',function ( error , data ) {
if ( error ) throw error
res.write( data )
res.end()
})
break
case '/fulian.jpg':
fs.readFile( './static/fulian.jpg', 'binary', function( error , data ) {
if( error ) throw error
res.write( data, 'binary' )
res.end()
})
break
default:
break
}
}).listen( 8000, 'localhost', function () {
console.log( '服務器運行在: http://localhost:8000' )
})
五辫红、靜態(tài)資源服務
5.1 readStaticFile
/modules/readStaticFile.js
// 引入依賴的模塊
var path = require('path')
var fs = require('fs')
var mime = require('mime')
function readStaticFile(res, filePathname) {
var ext = path.parse(filePathname).ext
var mimeType = mime.getType(ext)
// 判斷路徑是否有后綴, 有的話則說明客戶端要請求的是一個文件
if (ext) {
// 根據(jù)傳入的目標文件路徑來讀取對應文件
fs.readFile(filePathname, (err, data) => {
// 錯誤處理
if (err) {
res.writeHead(404, { "Content-Type": "text/plain" })
res.write("404 - NOT FOUND")
res.end()
} else {
res.writeHead(200, { "Content-Type": mimeType })
res.write(data)
res.end()
}
});
// 返回 true 表示, 客戶端想要的 是 靜態(tài)文件
return true
} else {
// 返回 false 表示, 客戶端想要的 不是 靜態(tài)文件
return false
}
}
// 導出函數(shù)
module.exports = readStaticFile
5.2 server
/server.js
// 引入相關(guān)模塊
var http = require('http');
var url = require('url');
var path = require('path');
var readStaticFile = require('./modules/readStaticFile');
// 搭建 HTTP 服務器
var server = http.createServer(function(req, res) {
var urlObj = url.parse(req.url);
var urlPathname = urlObj.pathname;
var filePathname = path.join(__dirname, "/public", urlPathname);
// 讀取靜態(tài)文件
readStaticFile(res, filePathname);
});
// 在 3000 端口監(jiān)聽請求
server.listen(3000, function() {
console.log("服務器運行中.");
console.log("正在監(jiān)聽 3000 端口:")
})
5.3 最終目錄結(jié)構(gòu)
[圖片上傳失敗...(image-f47052-1651418882033)]