当前位置: 首页 > news >正文

nodejs笔记

概念

Node.js是一个javascript运行环境,它让javascript可以开发后端程序,实现几乎其他后端语言实现的所有功能,可以与php、java、paython、.net、ruby等后端语言平起平坐。

模快、包、commonjs

  1. 为什么要有模块化开发
    在这里插入图片描述
  2. CommonJs规范
    在这里插入图片描述
  3. modules模块化规范写法
    可以把公共的功能 抽离成为一个单独的js文件 作为一个模块,默认情况下面这个模块里面的方法或者属性,外面是没办法访问的,如果让外部访问模块里面的方法或属性,就必须在模块里面通过exports或者module.exports暴露属性或者方法。
  4. Npm & Yarn
  • npm的使用
npm init 
npm install 包名 -g (uninstall, update)
npm install 包名 --save-dev (uninstall,update)
npm list -g (不加-g, 列举当前目录下的安装包)
npm info 包名(详细信息)npm info 包名 version(获取最新版本)
npm install md5@1(安装指定版本)
npm outdated(检查包是否已经过时)"dependencies": { "md5": "^2.1.0" } ^表示 如果直接 npm install 将会安装md5 2.*.* 最小版本
"dependencies": { "md5": "~2.1.0" } ~表示 如果直接 npm install 将会安装md5 2.1.*最新版本
"dependencies": { "md5": "*" } * 表示 如果直接npm install将会安装md5最新版本

全局安装nrm

nrm是npm的镜像源管理工具,有时候国外资源太慢,使用这个就可以快速地在npm源间切换。
手动切换方法:npm config set registry https://registry.npm.taobao.org

安装nrm
npm install -g nrm 
使用nrm

执行命令nrm ls 查看可选的源,其中,带*的是当前使用的源,上面的输出表明当前源是官方源

切换nrm

如果要切换到taobao源,执行命令nrm use taobao

测试速度

可以通过nrm test测试相应源的响应速度

npm install -g cnpm --registry=https://registry.npmmirror.com

yarn使用

npm install -g yarn
对比npm:速度超快:Yarn缓存了每个下载过的包,所有再次使用时无需重复下载,同时利用并行下载以最大化资源利用率,因此安装速度快,超级安全:在执行代码之前,Yarn会通过算法校验每个安装包的完整性。
开始项目 yarn init
添加依赖包yarn add [package]yarn add [package]@[version]yarn add [package] --dev
升级依赖包yarn upgrade [package]@[version]
移除依赖包yarn remove [package]  
安装项目的全部依赖yarn install

内置模块

  1. http模块
    要使用HTTP服务器和客户端,则必须require(‘http’)
const http = require('http')
// 创建本地服务器来从其接受数据
const server = http.createServer((req, res) => {res.writeHead(200, { 'content-Type': 'application/json' })res.end(JSON.stringify({data: 'hello world'}))
})
server.listen(8000)
const http = require('http')
// 创建本地服务器来从其接受数据
const server = http.createServer()// 监听请求事件
server.on('request', (request, res) => {res.writeHead(200, { 'Content-type': 'application/json' })res.end(JSON.stringfy({data: 'hello world'}))
})server.listen(8000)
  1. url模块
  • 2.1 parse
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)
  • 2.2 format
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'
}
const parseobj = url.format(urlObject)
console.log(parseobj)
  • 2.3 resolve
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)
  1. querystring模块
  • 3.1 parse 将字符串转成对象
const querystring = require('querystring')
var qs = 'x=3&y=4'
var parsed = querystring.parse(qs)
console.log(parsed) // {x:3, y: 4}
  • 3.2 stringify 将对象转成字符串
const querystring = require('querystring')
var qo = {x: 3,y: 4
}
var parsed = querystring.stringify(qo)
console.log(parsed) // x=3&y=4
  • 3.3 escape/unescape
    在这里插入图片描述
    这时正常情况下能查询到一条数据,如果将param修改成
    let param = ‘ns"–’
    sql语句就会变成 select*from tb_nature where nature = ‘ns’–" and del_status=1后面的del_status机会被参数中的–注释掉,失去作用,能查询到到多条数据。
    如果对param使用escape包装下,就能将参数中的特性字符进行转义,防止sql的注入。let sql = ‘select *from tb_nature where nature=’ + mysql.escape(param) + ‘and del_status=1’
const querystring = require('querystring')
var str = 'id=3&city=北京&url=https://www.baidu.com'
var escaped = querystring.escape(str)
console.log(escaped) // id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com
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) // id=3&city=北京&url=https://www.baidu.com
  1. http模块补充
  • 4.1 接口: 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')
})
  • 4.2 跨域: 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'}))}}
})
  • 4.3 get
var http = require('http')
var https = require('https')
var url = require('url')http.createServer((req, res) => {var urlobj = url.parse(req.url, true)res.writeHead(200, {'Content-type': 'application/json;charset=utf-8','Access-control-Allow-Origin': '*'})switch(urlobj.pathname) {case "/api/aaa":httpget(data=> {res.end(data)})break;default : res.end('404')    }
}).listen(3000)function httpget(cb) {var data = ''https.get('xxx.com', (res) => {res.on('data', (chunk) => {data+=chunk})res.on('end', () => {cb(data)})})
}
  • 4.4 post
var http = require('http')
var https = require('https')
var url = require('url')http.createServer((req, res) => {var urlobj = url.parse(req.url, true)res.writeHead(200, {'Content-type': 'application/json;charset=utf-8','Access-control-Allow-Origin': '*'})switch(urlobj.pathname) {case "/api/aaa":httpPost(data => {res.end(data)})break;default : res.end('404')    }
}).listen(3000)function httpPost(cb) {var data = ''var options = {hostname: 'xxx.com',port: '443',path: '路径',method: 'POST',headers: {"Content-Type": 'application/json'}}var req = https.request(options, (res) => {res.on('data', chunk => {data+=chunk})res.on('end', () => {cb(data)})})req.write(JSON.stringify([{},{"baseParam":{"ypClient": 1}}]))req.end()
}
  • 4.5 爬虫
var http = require('http')
var https = require('https')
var url = require('url')var cheerio = require('cheerio');http.createServer((req, res) => {var urlobj = url.parse(req.url, true)res.writeHead(200, {'Content-type': 'application/json;charset=utf-8','Access-control-Allow-Origin': '*'})switch(urlobj.pathname) {case "/api/aaa":httpget(data => {res.end(spider(data))})break;default : res.end('404')    }
}).listen(3000)function httpget(cb) {var data = ''https.get('xxx.com', (res) => {res.on('data', (chunk) => {data+=chunk})res.on('end', () => {cb(data)})})
}function spider(data) {let $ = cheerio.load(data)let $moviewList = $('.column.content')let movies = []$moviewList.each((index, value) => {movies.push({title: $(value).find('.title').text(),grade: $(value).find('.grade').text(),actor: $(value).find('.actor').text()})})// console.log(movies)return JSON.stringify(movies)
}
  1. event模块
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', '中国机长')
  1. fs文件操作模块
const fs = require('fs')
const fsp = require('fs').promises
// 创建文件夹
fs.mkdir('./logs', (err) => {console.log('done.')
})
// 文件夹改名
fs.rename('./logs', './log', () => {console.log('done')
})
// 删除文件夹
fs.rmdir('./log', () => {console.log('done.')
})
// 写内容到文件里
fs.writeFile('./logs/log1.txt', 'hello', (err) => {if(err) {console.log(err.message)} else {console.log('文件创建成功')}
})
// 追加内容到文件里
fs.appendFile('./avatar/a.txt', '\n你好', err => {console.log(err)
})
// 读取文件内容
fs.readFile('./avatar/a.txt','utf-8', (err, data) => {if(!err) {console.log(data)}
})
// 删除文件
fs.unlink('./avatar/a.txt', err => {console.log(err)
})
// 批量写入
for(var i=0;i<10;i++) {fs.writeFile(`./logs/log-${i}.txt`, `log-${i}`, err => {console.log('done.')})
}
// 读取文件/目录信息
fs.readdir('./avatar', (err, data) => {data.forEach((value, index) => {fs.stat(`./${value}`, (err, stats) => {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)
}
// 异步读取文件,方法一
fs.readFile('./logs/log-0.txt', 'utf-8', (err, content) => {console.log(content)console.log(0)
})
console.log(1)
// 异步读取文件: 方法二
const fs = require('fs').promises
fs.readFile('./logs/log-0.txt', 'utf-8').then(result => {console.log(result)
})
// 判断是文件夹还是文件
fs.stat('./avatar', (err, data) => {console.log(data.isFile())console.log(data.isDirectory())
})

在fs模块中,提供同步方法是为了方便使用,那我们到底是应用异步方法还是同步方法
由于Node环境执行的javascript代码是服务器代码,所有,绝大部分需要在服务器运行期反复执行业务逻辑的代码,必须使用异步代码,否则,同步代码在执行期,服务器停止响应,因为javascript只有一个执行线程。服务器启动时如果需要读取配置文件,或者结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。

  1. stream流模块
    stream是nodejs提供的又一个仅在服务端可用的模块,目的是支持流这种数据结构。
    什么是流?流是一种抽象的数据结构。想象水流,当在水管中流动时,就可以从某个地方源源不断地到达另一个地方。我们也可以把数据看做成是数据流,比如你敲键盘的时候,就可以把每个字符依次连起来,看成字符流。这个流是从键盘输入到应用程序,实际上它还对应一个名字,标准输入流

如果应用程序把字符一个一个输出到显示器上,这也可以看成是一个流, 这个流也有名字:标准输出流。流的特点是数据是有序的,而且必须依次读取,或者依次写入,不能像Array那样随机定位。
有些流用来读取数据,比如从文件读取数据时,可以打卡一个文件流,然后从文件流中不断地读取数据,有些流用来 写入数据,比如同文件写入数据时,只需要把数据不断地往文件流中写进行就可以。
在nodejs中,流也是一个对象,我们只需要响应流的事件就可以;data事情表示流的数据已经可以读取了,end事件表示这个流已经到末尾了,没有数据可以读取了,error事件表示出错了。

var fs = require('fs')// 打开一个流
var rs = fs.createReadStream('sample.txt', 'utf-8')rs.on('data', function(chunk) {console.log('DATA:')console.log(chunk)
})rs.on('end', function(){console.log('end')
})rs.on('error', function(err){console.log('error' + err)
})

要注意,data事件可能会有多次,每次传递的chunk是流的一部分数据。
要以流的形式写入文件,只需要不断调用write()方法,最后以end()结束;

var fs = require('fs')
var ws1 = fs.createwritestream('output1.txt', 'utf-8')
ws1.write('使用stream写入文本数据...\n')
ws1.write('end.')
ws1.end()

pipe就像可以把两个水管串成一个更长的水管一样,两个流也可以串起来。一个readable流和一个writeable流串起来后,所有的数据自动从readable流进入writable流,这种操作叫pipe
在nodejs中,readable流有一个pipe()方法,就是用来干这个事情的
让我们用pipe()把一个文件流和另一个文件流串起来,这样源文件的所有数据就自动写入到目标文件里了,所有,这实际上是一个复制文件的程序。

const fs = require('fs')const readstream = fs.createReadStream('./1.txt')
const writestream = fs.createwriteStream('./2.txt')
readstream.pipe(writestream)
  1. 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)
  1. crypto
    crypto模块目的是为了提供通用的加密和哈希算法。用纯javascript代码实现这些功能不是不可能,但速度会非常慢,nodejs用c/c++实现这些算法后,通过crypto这个模块暴露为javascript接口,这样用起来很方便,运行速度也快。
    MD5是一种常用的哈希算法,用于给任意数据一个签名,这个签名通常用一个十六进制的字符串表示:
const crypto = require('crypto')
const hash = crypto.createHash('md5')
// 可任意多次调用update()
hash.update('hello, world!')
hash.update('hello, nodejs!')
console.log(hash.digest('hex'))

update()方法默认字符串编码为UTF-8,也可以传入Buffer
如果要计算SHA1,只需要把’MD5’改成‘sha1’,就可以得到SHA1的结果
5eb63bbbe01eeed093cb22bb8f5acdc3
Hmac算法也是一种哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac还需要一个密钥:

const crypto = require('crypto')
const hmac = crypto.createHmac('sha256', 'secret-key')
hmac.update('hello, world!')
hmac.update('hello,nodejs!')
console.log(hmac.digest('hex'))

只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数增强的哈希算法。
AES是一种常用的对称算法,加解密都用同一个密钥。crypto模块提供了AES支持,但是需要自己封装好函数,便于使用:

const crypto = require('crypto')function encrypt(key, iv, data) {let decipher = crypto.createCipheriv('aes-128-cbc', key, iv)// decipher.setAutoPadding(true)return decipher.update(data, 'binary', 'hex') + decipher.final('hex')
}function decrypt(key, iv, crypted) {crypted = Buffer.from(crypted, 'hex').toString('binary')let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv)return decipher.update(crypted, 'binary', 'utf8') + decipher.final('utf8')
}

Express

https://www.expressjs.com.cn
基于nodejs平台,快速、开放、极简的web开发框架

  1. 安装
npm install express --save
  1. 路由
var app = express()app.get('/', (req, res) => {res.send('hello world')
})

路由路径和请求方法一起定义了请求的端点,它可以是字符串、字符串模式或者正则表达式。

// 匹配根路径的请求
app.get('/', function(req, res) {res.send('root')
})// 匹配 /about路径的请求
app.get('/about', function(req, res) {res.send('about')
})// 匹配 /random.text路径的请求
app.get('/random.text', function(req, res){res.send('random.text')
})

使用字符串模式的路由路径实例:

// 匹配 acd 和 abcd
app.get('/ab?cd', function(req, res) {res.send('ab?cd')
})
// 匹配 /ab/****
app.get('/ab/:id', function(req, res) {res.send('aaaaaa')
})
// 匹配abcd、abbcd、abbbcd等
app.get('/ab+cd', function(req, res){res.send('ab+cd')
})
// 匹配abcd、abxcd、abRABDOMcd、ab123cd等
app.get('/ab*cd', function(req, res){res.send('ab*cd')
})
// 匹配 /abe 和 /abcde
app.get('/ab(cd)?e', function(req, res) {res.send('ab(cd)?e')
})

使用正则表达式的路由路径实例:

// 匹配任何路由中含有 a 的路径
app.get(/a/, function(req, res){res.send('/a/')
})// 匹配butterfly, dragonfly, 不匹配 butterflyman、dragonfly man 等
app.get(/.*fly$/, function(req, res){res.send('/。*fly$/')
})

可以为请求处理提供多个回调函数,其行为类似中间件。唯一区别的这些回调函数可能调用next(‘route’)方法而略过其他路由回调函数,可以利用这机制为路由定义前提条件,如果在现有路径上继续执行没有意义,则可将控制权交给剩下的路径。

app.get('/example/a', function(req, res){res.send('hello from A!')
})
  1. 中间件
    Express是一个自身功能极简,完全是由路由和中间件构成一个的web开发框架;从本质上来说,一个Express应用就是在调用各种中间件。
    中间件(middleware)是一个函数,它可以访问请求对象(request object(req)),响应对象(response object(res)),和web应用中处于请求-响应循环流程中的中间件,一般被命名为next的变量。
    中间件的功能包括:
  • 执行任何代码
  • 修改请求和响应对象
  • 终结请求-响应循环
  • 调用堆栈中的下一个中间件。
    如果当前中间件没有终结请求-响应循环,则必须调用next()方法将控制权交给下一个中间件,否则请求就会挂起。
    Express 应用可使用如下几种中间件
  • 应用级中间件
  • 路由级中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

使用可选则挂载路径,可在应用级别或路由级别装载中间件,另外,你还可以同时装在一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。

  1. 应用级中间件
    应用级中间件绑定app对象,使用app.use()和app.METHOD(),其中,METHOD是需要处理的HTTP请求的方法,列如:GET、PUT、POST等等,全部小写。列入:
var app = express()
// 没有挂载路由的中间件,应用的每个请求都会执行该中间件
app.use(function(req, res, next){console.log('Time:', Date.now())next()
})
  1. 路由级中间件
    路由级中间件和应用级中间件一样,只是它绑定的对象为experss.Router()
var router = express.Router()
var app = express()
var router = express.Router()
// 没有挂载路径的中间件,通过该路由的每个请求都会执行该中间件
router.use(function(req, res, next){console.log('Time:', Date.now())next()
})
// 一个中间件,显示任何指向/user/:id 的HTTP请求的信息
router.use('/user/:id', function(req, res, next) {console.log('Request URL:', req.originaUrl)next()
}, function(req, res, next) {console.log('Request Type:', req.method)next()
})// 一个中间件栈,处理指向 /user/:id 的get请求
router.get('/user/:id', function(req, res, next) {// 如果user id 为0,跳到下一个路由if(req.params.id == 0) next('route')// 负责将控制权交给栈中下一个中间件else next()
}, function(req, res, next) {// 渲染常规页面res.render('regular')
})
// 处理 /user/:id 渲染一个特需页面
router.get('/user/:id', function(req, res, next) {console.log(req.params.id)res.render('special')
})// 将路由挂载至应用
app.use('/', router)
  1. 错误处理中间件
    错误处理中间件和其他中间件定义类似,只是要使用4个参数,而不是3个,其签名如下:(err, req, res, next)
app.use(function(err, req, res, next) {console.log(err.stack)res.status(500).send('something broke!')
})
  1. 内置的中间件
    express.static是Express唯一内置的中间件,它基于serve-static,负责在Express应用中提托管静态资源,每个应用可有多个静态目录
app.use(express.static('public'))
app.use(express.static('uploads'))
app.use(express.static('files'))
  1. 第三方中间件
    安装所需功能的node模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。
    下面的例子安装并加载了一个解析cookie的中间件:cookie-parser
npm install cookie-parser
var express = reqiure('express')
var app = express()
var cookieParser = require('cookie-parser')// 加载用于解析cookie的中间件
app.use(cookieParser())

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 聚观早报 | 淘宝将支持微信支付;董明珠支持招35岁员工
  • AE调试一些记录(1)
  • 探索NVIDIA RTX 4060 8G与RTX 3060 12G:性能与适用场景的深度解析
  • 从零开始,认识游戏设计师(3)体验源于设计师①
  • 苹果手机怎么设置铃声?3个方法教你制定个性化铃声
  • 鲁大师8月新机性能/流畅/AI/久用榜:新机节奏放缓,但不乏小惊喜
  • Linux malloc内存分配实现原理
  • 828华为云征文 | Flexus X实例与Harbor私有镜像仓库的完美结合
  • armbian cups 远程打印机 1022
  • 「OC」iOS事件处理流程
  • Vu3 跨组件通讯
  • ASPICE评估前的重要准备事项
  • 【 html+css 绚丽Loading 】000037 六合归一心
  • Oracle 和 PostgreSQL 常用数据类型的对比
  • 2024前端面试题分享
  • 【Leetcode】104. 二叉树的最大深度
  • 【知识碎片】第三方登录弹窗效果
  • canvas 绘制双线技巧
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • java概述
  • jdbc就是这么简单
  • PV统计优化设计
  • React中的“虫洞”——Context
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • Windows Containers 大冒险: 容器网络
  • windows-nginx-https-本地配置
  • 闭包,sync使用细节
  • 从0实现一个tiny react(三)生命周期
  • 复杂数据处理
  • 试着探索高并发下的系统架构面貌
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • 组复制官方翻译九、Group Replication Technical Details
  • #nginx配置案例
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • $$$$GB2312-80区位编码表$$$$
  • $refs 、$nextTic、动态组件、name的使用
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (1)虚拟机的安装与使用,linux系统安装
  • (160)时序收敛--->(10)时序收敛十
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (七)Knockout 创建自定义绑定
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (太强大了) - Linux 性能监控、测试、优化工具
  • .gitignore文件---让git自动忽略指定文件
  • .libPaths()设置包加载目录
  • .net 7和core版 SignalR
  • .net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript
  • .NET Framework杂记
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • /etc/motd and /etc/issue
  • @PreAuthorize与@Secured注解的区别是什么?