Author:@德玛玩前端
Date: 2023-07-06
Nodejs
一、Nodejs概述
1.1、什么是JavaScript
1995年由Netscape公司退出,后经ECMA统一标准的脚本语言。通常狭义上理解的JS是指在浏览器内置的JS解释器中运行的,主要用途是操作网页内容,实现用户交互
1.2、什么是Nodejs
2009年由Ryan Dahl开发,现由Nodejs Foundatuin维护,基于Google V8引擎的JS运行时环境,其运行完全脱离浏览器,可以编写独立的服务器端程序,主要用途为文件读写,网络访问,加密压缩,数据库操作等。
官网网站:www.nodejs.org
中文镜像网站:www.nodejs.cn
1.3 Javascript 和 Nodejs的区别
- 使js既可以编写客户端应用,又可以编写服务端应用了。一种语法统一前后端。
- 区别
- js属于客户端技术,运行在浏览器。nodejs是服务端技术,与PHP、JSP等是类似的技术
- js有多种解释器可以使用,如ie的chakra,ff的猴子系列,chrome的v8等等,nodejs运行于基于v8引擎改进而来的运行时环境
- js因为解释器有多种,所有存在代码兼容性问题,nodejs只有一种解释器,所以不存在代码兼容性问题。
- js 对象包括:ES原生对象,用户自定义独象,宿主对象(例如 DOM & BOM对象);nodejs 对象包括:ES原生对象,用户自定义对象,Nodejs扩展对象。
- js主要用于网页DOM元素的操作,实现用户交互效果,主要用于实现服务器端进行逻辑,如文件系统操作,数据库访问,其他服务器调用等。
二、安装和检测
-
安装步骤 【nodejs官方有安装说明支持】
-
安装后检测是否安装完成
widow + R输入"cmd"node -v查看当前nodejs的版本号npm -v附带的安装工具,查看版本号可检测node是否安装完成
-
进入交互模式
node + 回车进入交互模式ctrl+c 两次 / exit退出交互模式
-
交互模式和脚本模式的区别
- 交互模式(REPL模式 Read-Evaluate-Print-Loop )
- 读取用户输入,执行运算,输出执行结果,继续下一次循环
- 交互模式下,Nodejs自带的模块无需引入
- 脚本模式
- 将所有语句编写在独立的脚本文件中,一次性执行
- 脚本模式下,除了全局对象以其相关成员外,所有其他模块中声明的对象和方法必须使用require引入
- 交互模式(REPL模式 Read-Evaluate-Print-Loop )
三、Nodejs的体系结构
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c8Gnbcum-1688651272348)(https://note.youdao.com/yws/res/28788/WEBRESOURCEc3c34b09e63df2beb941dbaf9d58b67a)]](https://img-blog.csdnimg.cn/15e46835d90f43b3a12471c3cc3a0b35.png)
四、Node.js的语法
-
Nodejs语法是基于JavaScript的。下列内容与JS是完全一样的
- 数据类型
- 声明变量和常量
- 运算符
- 逻辑结构
- 函数作用域和闭包
- 对象和原型
- 对象分类
-
Nodejs的数据类型
-
原始类型(Primitive Type)
- string、number、boolean、null、undefined
-
引用类型 (Reference Type)
- ES核心对象 Global String Number Boolean Date Math Ar
ray Error Function Object RegExp - Nodejs对象:Buffer ReadStream ClientRequest
- 自定义对象
- ES核心对象 Global String Number Boolean Date Math Ar
-
五、Node.js的特点
- 简单,避免过渡设计
- 单线程逻辑处理
- 非阻塞的异步I/O处理
- 事件驱动编程
- 无锁机制,不会产生死锁
- 支持数万个并发连接 (承载访问量大,腾讯使用)
- Node.js适合搭建以IO操作为主,响应速度快,易于扩展的网络应用,例如
- 命令行工具
- 带有GUI界面的本地应用程序
- 交互式终端程序
- 基于社交网络的大规模web应用
- web socket服务器
- TCP/UDP套接字程序
- 客户端javascript编译器
- Nodejs不适合CPU密集型应用
- 深层次的嵌套和递归
- 复杂加密和解密算法
- 高可靠性运算
- 严格内存管理
- 数据挖掘和数据分析
六、Nodejs对象
6.1、global 全局对象
-
详见官网 https://nodejs.org/dist/latest-v14.x/docs/api/globals.html#globals_console
-
在交互模式下,声明的变量和创建的函数都是global下的,例如
global.aglobal.fn() -
在脚本模式下,声明的变量和创建的函数都不是global下的
// global.fn is not function -
但是,在js下,声明的变量和创建的函数都是在全局window下,例如window.a、window.fn()
6.2、console对象
-
console.log()打印日志 -
console.info()打印消息 -
console.warn()打印警告 -
console.error()打印错误 -
console.time()开始计时 -
console.timeEnd()结束计时 //开始计时和结束计时的字符串要保持一致console.log(1); console.info(2); console.warn(3); console.error(4);//浏览器下看,nodejs下看不出区别 console.time('for') for(let i=1;i<10000;i++){ //..... } console.timeEnd('for') -
小案例:查看相同情况下,for while do-while 哪一个更快
console.time('for') for(let i=1;i<=10000;1++){ } console.timeEnd('for') console.time('while') let i=1;//let 不能反复的声明变量 while(i<=10000){ i++ } console.timeEnd('while') console.time('do-while') i=1; do{ i++ }while(i<=10000) console.timeEnd('do-while')![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RkX1ELjA-1688651272350)(https://note.youdao.com/yws/res/28759/WEBRESOURCE2ccde4844eef8adad5e809460ff51d3c)]](https://img-blog.csdnimg.cn/13b65f8a12d64e638cb04e8f1e1e0cf1.png)
6.3、process 进程对象
交互模式下使用
process.arch 查看当前cpu的架构
process.platform 查看当前的操作系统
process.version 查看当前的操作系统
process.env 查看当前计算机的环境变量有哪些
process.kill() 结束某个编号的进程
process.pid 查看当前进程的编号
6.4、Buffer对象
缓冲区:在内存中临时存储数据的区域,常用于网络传输时的资源,程序结束就消失。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lrc7o86c-1688651272351)(https://note.youdao.com/yws/res/28761/WEBRESOURCEcd67a09e51cf287c07d094ab07c5aaa0)]](https://img-blog.csdnimg.cn/57f77241292b4443b81ee3f6f28e9bea.png)
//创建buffer
let buf=Buffer.allow(6,'23a22d')// 6个字符,存储的数据
//Buffer数据使用时需要转字符串
console.log(buf.tostring())//获取的buffer数据(unicode码)转字符串
//console.log(string(buf))
6.5、timer 定时器 (全局函数)
-
setTimeout(callback,delay) / clearTimeout(tiemr) 一次定时器
-
setInterval(callback,delay) / clearInterval(tiemr) 周期定时器
-
setImmediate(callback) / clearImmediate(tiemr) 立即执行器
-
process.nextTick(callback)
console.log(2) setImmediate(()=>{ console.log(1) }) process.nextTick(()=>{ console.log(4) }) //process.nexTick中的回调函数会放在主线程的最后 console.log(3) // 2 3 4 1
七、模块系统
-
模块:就是一个独立的功能体
-
分为3类:自定义模块,核心模块,第三方模块
-
Nodejs下规定,以一个文件就是一个模块,模块中的每一个变量和函数不能被web访问,模块中的代码被一个构造函数所包含,模块外部无法得到。
(function(exports,require,module,__filename,__dirname){ //代码 ............. }) -
引入模块往往用常量保存,常量名称通常就是模块的名字。
7.1、require()
用于引入另一个模块(对象)属性以及内容,同一级必须添加./,后缀名可以省略。
7.2、exports
如果导出的对象为空,可以往对象中添加导出的内容。
案例:
创建两个模块,主模块main.js和功能模块circle.js,在功能模块下创建两个函数,传递半径计周长和面积,导出这两个函数;在主模块下引入,并调用两个函数。
//main.js
const circle=requrie('./circle.js') //引入一个模块默认都是对象
//console.log(circle)
console.log(circle.getArea(5).toFixed(2))
console.log(circle.getLength(5).toFixed(2))
console.log(circle.add(2,3))//5
//circle.js
function getArea(r){
return Math.PI*Math.pow(r,2)
}
function getLength(r){
return Math.PI*2*r
}
export.getArea=getArea
export.getLength=getLength //添加导出对象
exports.add=(a,b)=>a+b;
//exports={}
7.3、module
当前的模块对象
module.exports 当前模块要导出的对象
exports 导出对象的别名,等价于modules.exports
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yTPwr0fG-1688651272352)(https://note.youdao.com/yws/res/28766/WEBRESOURCE82a59dd47b969c2cb9f8dff117edf095)]](https://img-blog.csdnimg.cn/6be76b63f7af405e8d2f6c9e118664e5.png)
//都可以添加
exports.a=1
mpdules.exports.b=3
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWAA52oL-1688651272353)(https://note.youdao.com/yws/res/28768/WEBRESOURCE28786644ec8ea4584eb89211e44787cb)]](https://img-blog.csdnimg.cn/4539145adc354c3fa478cbff04077d86.png)
// 用一个新的对象作为导出对象
module.exports=emp
console.log(exports===module.exports) //false
7.4、__filename
当前模块的绝对路径+模块名称(文件名)
7.5、__dirname
当前模块的绝对路径 directory
7.6、require() 模块的引入
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OlX9ffUk-1688651272354)(https://note.youdao.com/yws/res/28770/WEBRESOURCE0d6f03146bcacbd4d44181407d33dc3f)]](https://img-blog.csdnimg.cn/33f6df3a46884fe7840c9b4f84d34bf1.png)
-
自定义模块
-
require('./cicrle.js')// 路径方式引入js文件 -
require('./circle')// 路径方式引入js文件,后缀名可以省略 -
require('./dir')// 模块方式引入,需要初始化文件package.json, 优先引入文件中main属性对应的文件名,默认是index.js
-
-
第三方模块
- 使用前提:npm下载到node_modules
- require(‘mysql’) 默认引入index.js
-
核心模块
- require(‘fs’)
- 直接引用 nodejs官网提供
八、核心模块(官方提供的内置模块)
8.1、querystring模块–查询字符串
查询字符串是什么?传递数据
浏览器向web服务器发送请求,传递数据的一种方式,位于URL中间号后的部分
http://www.baidu.com/list.html?username="dema" & age=22'
包含的api:
parse() 将查询字符串解析为对象
stringify() 将对象格式化为查询字符串
// 引入查询字符串模块
const qs=require('querystring') //自动从官方下载
let str="kw=dell&price=4999"
// 查询字符串解析为对象
let obj=qs.parse(str)
console.log(obj)
//将对象格式化为查询字符串
let obj2={
lid:18,
title:'dell'
}
let str2=qs.stringify(obj2)
console.log(str2) //lid=18&title=dell
8.2、URL模块–处理和解析URL
包含的Api:
parse()解析url为对象后,从而可以获得url中的任意部分
format() 将对象格式化为url,对象的字符串部分放的是对象
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GykNLXdu-1688651272355)(https://note.youdao.com/yws/res/28772/WEBRESOURCEbc257327ca2269db00b943a799010e60)]](https://img-blog.csdnimg.cn/a189ec220bc34af78942af402baab9b9.png)
console.log(url.parse(str))
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g55JksN2-1688651272356)(https://note.youdao.com/yws/res/28774/WEBRESOURCE65f7025cef24a73c4474a16cc745e652)]](https://img-blog.csdnimg.cn/a0aa48e08de8424882c68b3c9319b13a.png)
小案例:获取url中查询字符串的value值
// 思路
// 1. 引用url模块,将url转化成对象,拿到query的字符串
// 2. 引用querystring模块,先将query字符串转换成对象,在获取里面的value值
const url=require('url')
const qs=require('querystring')
let str="https://baidu.com/web/1.html?username='dema'&age=22"
let obj=url.parse(str)
let obj2=qs.parse(obj.query)
console.log('username',obj2.username,'age',obj2.age)
//username 'dema' age 22
8.3、fs 文件系统模块
8.3.1、查看是否为文件
-
fs.isFile()- 返回 ture 或 false
8.3.2、查看是否为目录
-
fs.isDirectory()- 返回true或false
8.3.3 查看文件状态
-
fs.stat(path,callback)异步获取-
这个api的获取通过callback,而不是通过返回值
-
path 文件的路径
-
callback 回调函数,用于获取结果
-
err 可能产生的结果
-
result 文件的结果状态
const fs=require('fs') //通过回调函数的第二个参数来打印结果 let res=fs.stat('homework.js',(err,result)=>{ if(err) throw err //抛出代码,组织代码向后运行 console.log(result) // result为局部作用域 })
-
-
fs.statSync(path)同步获取-
这个api结果的获取直接通过返回值
-
path 文件的路径
const fs=require('fs') let result=fs.statSync('homework.js') console.log(result)
-
8.3.4 创建目录
-
fs.mkdir(path,callback)异步创建const fs=require('fs') fs.mkdir('mkdir',(err)=>{ if(err) throw err; console.log('目录创建成功') }) // 线程池的 结果放进事件队列 console.log('end') //主程序的 // 执行结果: end 目录创建成功 -
fs.mkdirSync(path)同步创建const fs=require('fs') fs.mkdirSync('mkdir')//同步也是主程序 consoel.log('end')//主程序 // 执行结果: 先创建文件夹,再输出 end
8.3.5 移除目录
如果目录中有文件要先删除文件
-
fs.rmdir(path,callback)异步删除const fs=require('fs') fs.rmdir('mydir',(err)=>{ if(err) throw err console.log('移除成功') }) -
fs.rmdirSync(path)同步删除cosnt fs=require('fs') fs.rmdirSync('mydir')
8.3.6、读取目录
读取到的目录里的文件以数组的形式呈现
-
fs.readdir(path,callback)异步读取目录const fs=require('fs') fs.readdir('mkdir',(err,result)=>{ if(err) throw err console.log(result) }) -
fs.readdirSync(path)同步读取目录const fs=require('fs') let result=fs.readdirSync('mkdir') console.log(result)
8.3.7、创建文件并写入
-
fs.writeFile(path,data,callback)/fs.writeFileSync(path,data)- 创建文件和写入文件同一个api,因为写入的文件没有就是创建,如果文件有并且有数据,直接清空,然后写入新数据
- path 文件的路径
- data 写入的数据
const fs=require('fs') // 异步创建 fs.writeFile('1.txt','redu.cn',(err)=>{ if(err) throw err console.log('文件写入成功') }) //同步创建 fs.writeFileSync('2.txt','hello') -
fs.appendFile(path,data,callback)/fs.appendFileSync(path,data)- 如果文件不存在,先创建然后写入
- 如果文件存在,在文件的末尾追加写入
const fs=require('fs') //异步创建 fs.appendFile('1.txt','hello',(err)={ if(err) throw err console.log('追击使用成功') }) //同步创建 fs.appendFileSync('2.txt','hello') -
案例:使用同步创建文件的方法将后台获取的json数据写入文件’student.txt’中
const fs=require('fs') var arr=[ {eid:1,ename:'huwenhao',sex:1} {eid:2,ename:'king',sex:2} {eid:3,ename:'kawb',sex:0} ] for(var val of arr){ let str='序号'+val.eid+'姓名'+val.ename+'性别'+val.sex fs.appendFileSync('student.txt',str) }
8.3.8、读取文件
-
fs.readFile(path,callback)异步读取 -
fs.readFileSync(path)同步读取const fs=require('fs') //异步读取 fs.readFile('student.txt','utf-8',(err,data)=>{ if (err) throw err console.log(data) }) //同步读取 let data=fs.readFileSync('3.txt') console.log(data.toString())
8.3.9、删除文件
-
fs.unlink(path,callback)异步删除 -
fs.unlinkSync(path)同步删除const fs=require('fs') // 异步删除 fs.unlink('2.txt',(err)=>{ if(err) throw err console.log('删除成功') }) // 同步删除 fs.unlinkSync('2.txt')
8.3.10、检测文件或文件夹是否存在
-
异步已废除,只有同步方法
-
fs.existsSync(path)返回true和false,可做条件表达式const fs=require('fs') if(fs.existsSync('3.txt')){ fs.unlinkSync('3.txt') console.log('已经被删除') }else{ console.log('3.txt不存在') }
8.3.11、读取流
读取文件的方式,是先把数据存入内存中,然后再从内存中获取数据,如果读取的文件太大,会造成内存压力过大,所以就有了流的操作。分段放入内存,再把数据从内存中取出。
各种类型的数据,例如压缩包,txt,word等
压缩包里不是文本文档,转换为字符串会造成卡死
流读取大型文件,会分成几段读取,所以读取速度快
const fs=require('fs')
// 创建一个可读取的流
let readStream=fs.createReadStream('jj.txt')
// 事件:监听是否有数据流入内存
// data: 事件名称,监听数据的事件
// 通过回调函数来获取数据
let count=0
readStream.on('data',(chunk)=>{
// chunk就是获取的数据,要转成字符串
// console.log(chunk)
// console.log(chunk.toString())
count++ // 当文件大需要分段读取的时候,每度一段加1
})
// 读取结束的事件
readStream.on('end',()=>{
console.log(count)
})
8.3.12、写入的流
把读取的文件放入另一个文件里,最终实现拷贝效果适用于较大文件提高性能
const fs=require('fs')
// 创建可读取的流
let readStream=fs.createReadStream('jj.txt')
// 创建可写入的流
let writeStream=fs.createWriteStream('database.txt')
// 把读取的流通过管道添加到写入流 拷贝
readStream.pipe(writeStream)
8.3.13、普通小文件copy
fs.copyFile(src,dest,callback)异步拷贝fs.copyFileSync(src,dest)同步拷贝
// 拷贝小文件 例如微信传递一个文件也是copy的过程
const fs=require('fs')
fs.copyFile('jj.txt','jj2.txt')
8.4、http模块
-
模拟浏览器向另外的服务器发请求
-
http.get(url,callback) 向服务器发请求,通过回调函数获取结果
- url 请求得URL
- callback 回调函数,获取结果
const http=require('http') http.get('www.baidu.com',(res)=>{ res.on('data',(chunk)=>{ consle.log(chunk.toString()) }) })
-
http模块发送get请求
-
导入http模块
var http = require('http'); -
配置请求对象(请求方式,url,请求路径)
var options = { host: 'http://dema.com', port: 10077, method: 'GET', path: '/dema.txt', headers: { 'Content-Type': 'text/plain' } } -
http.request(地址,响应结果) 发送请求
//发送请求 var req=http.request(options.function(res){ let info="" //通过监听res的data事件,可以得到返回的结果 //返回的结果是一点一点拼接的,不是一次性接收完毕 res.on('data',function(chunk){ info+=chunk.toString() }) //监听data,数据什么时间接收完毕 res.on('end',function(err){ console.log(info) }) }) req.end()
-
-
http模块发送post请求
-
导入http模块
var http = require('http'); //POST多了一个请求参数的处理 var querystring = require('querystring'); -
配置请求对象(请求方式,url,请求路径)
//参数的处理 var data=querystring.stringify({ name:'zhangsan', age:20 }) //请求对象的设置 let options={ host:'www.dema.com', port:10077, method:'POST', path:'/2.txt', headers: { 'Content-Type': 'application/x-www-form-urlencode', //必须在请求头中设置内容的长度 'Content-Length': Buffer.byteLength(data) } } -
http.request(地址,响应结果) 发送请求
var req = http.request(option, (res) => { let info = '' //post请求返回的结果是一个BUffer类型的数据,需要转化 res.on('data', (chunk) => { info += chunk.toString(); }) res.on('end', (err) => { console.log(info); console.log(err); }) }) req.write(data) //把请求数据放在请求体里面 req.end()
-
-
-
创建web服务器
-
http.createServer()创建web服务器let app=http.createServer(); app.listen(8080) //监听端口 // 监听浏览器请求,并通过回调函数获取请求,以及做出响应 app.on('request',(req,res)=>{ //res 响应对象 //res.writeHead() 设置响应的状态码和头信息 //res.write() 设置响应的内容 //res.end() 结束并发送响应到客户端 // 返回响应的内容 res.write(' this is my first web') res.end() // 解决中文乱码 res.writeHead(200.,{'Content-Type':'text/html;charset=utf-8'}) res.write('') res.end() // 跳转到另一个url res.writeHead(302,{ Location:'http://baidu.com' }) res.end() //req 请求的对象 //req.url 请求的URL显示端口号后的部分,表示要获取的内容 //req.method 请求的方法 //req.headers请求的头信息 }) -
get传递的数据容易被浏览器缓存(历史记录的url会显示请求的字符串数据)
-
获取get请求的数据 (req.url)
const url=require('url') const qs=require('querystring') var params = qs.parse(url.parse(req.url).query); -
获取post请求的数据 (req.on())
事件:监听是否有数据传递,通过回调函数来获取数据
req.on('data',(chunk)=>{ // Chunk 就是传递的数据,格式是buffer,转为字符串后为查询字符串,需要解析为对象。 })
-
九、第三方模块
9.1、包(目录模块)和npm
commonJS规范 nodejs往服务器发展的一种规范
nodejs是由多个模块组成,每个模块都有自己独立的作用域,变量和方法。一个模块的变量和方法在其他是不可见的,即使映入其他的模块,在web中也是不可见的,一个模块属于半封闭状态,需要导出后,另一个模块才能引入并看到此模块的方法。require,exports,exportsmodules都是由commonJS提出的。
包:就是一个目录模块
npm: 用于管理包的工具。www.npmjs.com 全局前端放包处,例如:Mysql express koa egg 都是创建web服务器、构建后台的框架。
9.2、搭建第三方模块的使用环境
-
cmd切换到指定目录下,
npm init --y初始化生成package.json文件(项目包说明文件,会记录项目相关内容及包的信息),不加这个文件,不会下载到该位置 -
npm install express安装第三方模块,自动生成package-lock.json文件(记录依赖包的版本号)和node_modules文件夹(第三方模块的包和依赖包)。 -
npm install自动安装package.json 和 package-lock.json中记录的包以及对应的版本号。
【注】 因为依赖的包太多,node_modules的文件包较大,所有实际工作中,将项目拷贝给别人或者别人将项目拷贝过来,理由并不会有这个文件包,但是会有package.json和package-lock.json文件,执行npm install就会自动安装node_modules的文件。
9.3、express框架
9.3.1、安装
- 终端,cd到指定文件夹下
- 准备文件,
npm init -y生成文件package.json,不加这个文件,不会下载到该位置 - 安装,
npm install express,安装好后,会出现package-lock.json文件和node_modules文件夹。该文件下就会出现node_modules文件夹,里面是express的包和附带包。 - 启服务
const express=require('express') //创建web服务器 let app=express() //监听端口 app.listen(8080)
9.3.2、路由
每一个路由处理一个请求,并且都是独立的
app.Method(path,callback)
案例
-
和 http相比,不需要考虑标签和编码问题, 只能用一次send()
// 创建路由:根据请求的URL和方法做出响应 // get 请求的方法 /login请求的url callback做出的响应 app.get('/login',(req,res)=>{ //req请求的对象 //res响应的对象 res.send('<h2>德玛玩前端</h2>')//发送给客户端 }) -
响应发送文件
app.get('/list',(req,res)=>{ //响应文件 res.sendFile(__dirname+'/list.html') }) -
响应发生重定向
app.get('/study',(req,res)=>{ //跳转 res.redirect('http://www.dema.com') })
9.3.3、响应对象和请求对象
-
res 响应的对象
res.send()设置响应的内容并发送res.sendFile()响应文件并发送,文件需要使用绝对路径res.redirect()响应的重定向,跳转到另一个URL- 以上的方法只能执行一次,表示响应已经结束
-
req 请求的对象
req.url获取请求的urlreq.method获取请求的方法req.query获取查询字符串数据,并解析为对象req.params获取路由传参的数据,格式为对象
9.3.4、获取get请求的数据
-
Get传递的数据容易被浏览器缓存(历史记录的url会显示请求的字符串数据)
-
方式1:字符串传参
// 获取查询字符串数据,并自动解析为对象 cconsole.log(req.query) res.send('注册成功,用户名:'+req.query.uname) -
方式2:路由传参
// 路由传参 app.get('/pacckage/:pname',(req,res)=>{ //获取路由传参的数据 console.log(req.params.pname) })
9.3.5、获取post请求的数据
-
方式一:同http模块接收方式,用事件监听
-
事件:监听是否有数据传递,通过回调函数来获取数据
req.on('data',(chunk)=>{ // chunk 就是传递的数据,格式是buffer,转为字符串后为 })
-
-
方式二:安装express第三方中间件 body-parser(下方有详细解释)
9.3.6、express中间件
所有中间件的基础语法:app.use() (注:let app=express())
浏览器向服务器发请求,中间件可以拦截(过滤)请求,最终给路由提供服务的。
可分为:
- 应用级中间件
- 路由级中间件
- 内置中间件
- 第三方中间件
https://www.expressjs.com.cn/resources/middleware.html - 错误处理中间件
[注]:Expressjs 从4开始,只保留一个内置中间件,其他都作为第三方中间件使用。
应用级中间件
app.use(url,(req,res,next)=>{})
- url:表示中间件要拦截哪一个路由,对应路由的url,如果为空表示拦截所有的请求
- req res:在中间件中可以获取请求的对象,也可以做出响应
- next是一个函数,表示执行执行下一个中间件和路由
const express=require('express') let app=express() app.listen(8080) // 添加中间件,权限设置 app.use('/list',function(req,res,next){ if(req.query.uname!='root'){ res.send('没有权限') }else{ next() //下一个中间件或路由 } }) // 添加中间件,商品价格打9折 app.use('/shopping',(req,res,next)=>{ console.log(req.query) req.query.price*=0.9 next() }) //list接口 app.get('/list',(req,res)=>{ res.send('允许拿到数据....') }) //shopping接口 app.get('/shopping',(req,res)=>{ res.send('商品价格为'+req.query.price) })
路由级中间件(路由器)
-
主模块使用路由器:
express().use(url,Router) -
模块中创建路由器:
express.Router() -
管理各个模块的路由
-
实际开发过程中,web服务器里不会再有路由,所有的路由都由路由器管理
-
有多少功能模块,就有多少路由器
-
实际开发项目中,按功能模块划分:(每一项都是一个路由)
-
用户模块:注册 登录 我的收藏 个人中心 列表
-
商品模块:首页 列表 详情
-
购物车模块:添加 修改 删除
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Y5vG8FY-1688651272357)(https://note.youdao.com/yws/res/28777/WEBRESOURCE67a9cfcce9b334ffd4219c7e735785bc)]](https://img-blog.csdnimg.cn/46ee0b9ff6324a14b33ddfc16f54ffec.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vCIFRHsr-1688651272358)(https://note.youdao.com/yws/res/28779/WEBRESOURCE7eef03c175a651d3d484e8b5d5335e15)]](https://img-blog.csdnimg.cn/775df50c2f4b44ffaba3e1a2d2a8f19d.png)
-
内置中间件
-
app.use(express.static('public')) -
托管静态资源,把所有的静态资源托管到指定的目录,如果浏览请求文件,自动到该目录下寻找,不需要再创建路由响应文件
res.sendFile()。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W9H26Weh-1688651272358)(https://note.youdao.com/yws/res/28782/WEBRESOURCE259f88fa31df5b9d0967bb76a9e9ce2f)]](https://img-blog.csdnimg.cn/cb12a09dabb24f3ea1129f7dd85bb4b8.png)
const express=require('express') const qs=require('querystring') let app=express() app.listen(8080) app.use(express.static('public')) app.post('/myLogin',(req,res)=>{ req.on('data',(chunk)=>{ let obj=qs.parse(chunk.toString()) console.log(obj) }) res.send('登录成功') })
第三方中间件(模块)
1.body-parser 可以转换数据类型
-
安装:
npm install body-parser -
因为安装express后node_modules已经存在此中间件,所以不需要安装,直接使用
const express=require(express) const bodyParser=require('body-parser') cosnt qs=require('querystring') let app=express() app.listen(8080) //第三方中间件放在路由之前 app.use(bodyParser.urlencoded({ extended:false //false 表示内部解析为对象不使用qs,true表示使用qs模块,内部自动完成不需要手动引入qs模块。 })) // 创建对应的路由 // 接收post请求的参数,取代监听请求数据的方法 app.post('/myLogin',(req,res)=>{ console.log(req.body) console.log(req.body.username) console.log(req.body.password) // req.on('data',(chunk)=>{ // let obj=qs.parse(chunk.toString()) // console.log(obj) // }) })
2.compress 压缩
-
安装
npm install compressionconst compression=require('compression') express().use(compression()) // 使用方式1: // 可以用compression中间件压缩和处理静态内容。 // 要在 express.static() 之前使用 app.use(express.static(path.join(__dirname, 'public'))); // 使用方式2: // 在路由之前使用,路由里的文件响应到browser进行了压缩 app.get('/list',(req,res)=>{ res.sendFile(__dirname+'/public/list.html') })
9.4、mysql模块 连接数据库
-
安装
npm install mysql --save -
引入方式
const mysql=require('mysql') -
创建方式
mysql.createConnetion()mysql.createPool()线程池方式更高效
-
占位符
?:防止SQL注入,sql语句是用户输入的值![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KufcQcgg-1688651272359)(https://note.youdao.com/yws/res/28784/WEBRESOURCE092ec218202f2376a8c503a859792b98)]](https://img-blog.csdnimg.cn/532b99c580424fdf87a429bd6ebb1104.png)
-
执行对数据库的增删改善
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWhPBHeF-1688651272359)(https://note.youdao.com/yws/res/28786/WEBRESOURCE6dbc72fd24cfbce31208726bbe749937)]](https://img-blog.csdnimg.cn/2eb434724f844fc9bd3a2b8ec492a872.png)



















