官方网站 www.nodejs.org
中文镜像网站 www.nodejs.cn
js和node.js的区别
两者有相同的自定义对象和内置对象,不同的宿主对象
js运行在浏览器端,存在多款浏览器,有兼容性问题。用于开发浏览器端交互效果
node.js运行在服务器端,只有一种解释器,没有兼容问题。用于服务器端开发
查看node.js版本号 node -v
node.js的执行方式
脚本模式 node 拖拽的脚本文件
交互模式 node (然后直接回车) 为标准输出,所以可以直接写a就出来,交互模式下是全局对象
退出交互模式 两次ctrc+c
node.js特点
单线程逻辑处理
非阻塞的异步I/0处理
事件驱动编程
无锁机制,不会产生死锁
支持数万个并发连接
适合搭建以IO操作为主、响应速度快、易于扩展的网络应用(命令行工具、带有GUI界面的本地应用程序、交互式终端程序、单元测试工具、基于社交网络的大规模、web socket服务器、TCP/UDP套接子程序 客户端javascript编译器)
不适合cpu密集型应用(深层次的嵌套和递归、复杂加密和解密算法、高可靠性运算、严格内存管理、数据挖掘和数据分析)
node.js要用到的东西
链接:https://pan.baidu.com/s/1KKyAfrzLbaEU_GED63YiYw
提取码:fbnu
复制这段内容后打开百度网盘手机App,操作更方便哦
全局对象
global 检查变量和函数是否为全局的,如果是全局可以使用global访问。
浏览器下的全局对象 window
node.js下每个文件都是在一个模块作用域下,里面的变量和函数都是局部的,可以防止全局污染
console 控制台
log 打印日志
info 打印消息
warn 打印警告
error 打印错误
time 开始计时
timeEnd 结束计时
注意:开始计时和结束计时的内容要保持一致
process 进程
交互模式下
process.arch 查看当前cpu架构
process.platform 查看当前操作系统版本
process.version 查看node.js版本号
process.pid 查看当前node.js进程编号
process.kill() 结束指定编号的进程
Buffer
缓冲区,缓冲器,内存中存储数据的区域,通常用于存储网络传输的资源。比如腾讯视频中的某个电影,当你用流量看它时,它一般是先缓冲几分钟,看完就释放了,不会下载下来,之后接着往前缓冲。
Buffer.alloc 创建空间,存储数据
.toString() 转为字符串 一个汉字占3个字节
模块
模块是一个独立的功能体
模块经常使用的方式,一个模块引入另一个模块 或者某个模块引入了好几个其他模块
模块类型
他有三种类型,自定义模块,核心模块,第三方模块
require() 是一个函数,用于引入其他的模块,模块之前还需要写上路径,告诉它到哪里去找
同一级寻找 ./ 上一级../ 上上级 ../../
module 当前模块的对象
module.exports 当前模块导出的对象,默认是一个空对象,里面放想要导出的对象
模块自带的两个变量
—filename 当前模块的绝对路径和模块名称
__dirname 当前模块的绝对路径 dir--directory 目录
模块分类
以路径开头 | 不以路径开头 | |
文件模块 | require('./文件名') 用于引入自定义模块 | require('官方提供的核心模块') |
目录模块 | require('./目录名')到目录下寻找package.json文件中main属性对象的文件,一般默认为index.js文件 | require("ran')会到同一级目录下的node_modules目录中寻找,如果找不到会一直往上一级目录中的node_modules中寻找;用于引入第三方模块 |
自定义模块
自己创建的模块
一个js文件就是一个模块,模块的作用域是局部的,不能直接访问
案例1:把eye.js文件引入face.js
案列2:对象
//写法2
module.exports=person;
之后引入直接
const person=require('./person.js');
目录模块
目录下默认为index.js文件 (必须写为index,默认)
如果目录模块中有几个文件,用json文件里的mian来指定要访问的文件
如果不用路径寻找目录模块的话,就使用node_moudles寻找,这种方式不用写路径,直接写目录模块名
核心模块
核心模块 node.js官方提供的
查询字符串模块 querystring
查询字符串:浏览器端向服务器端发请求传递数据的一种方式,位于url中,就是浏览器地址中的网址后?后面的内容
查询字符串模块用于操作查询字符串
URL模块
url:统一资源定位,互联网上任何的资源都有对应url,url由协议、域名/ip地址、端口、路径、查询字符串组成
http://www.codeboy.com:9999/product_detail.html?name="电脑"&price=10000
协议 域名/ip地址 端口 /开头为路径 ?开头为查询字符串
parse() 将url解析为对象,可以获取url中的各部分
定时器模块 timer setTimeout setInterval
提供了一组全局的函数,不需要引入模块(只要是全局函数,不需要引入模块)
一次性定时器
setTimeout(回调函数,间隔时间)
清除
clearTimeout(timer)
![](https://i-blog.csdnimg.cn/blog_migrate/30713ad6df86d9e42f6ca3225cc76aa0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4d1c3d86805a472d4a599fb6d5ef3766.png)
周期性定时器
setInterval(回调函数,间隔时间) 每隔一段时间调用一次回调函数 回调函数还是不懂
清除
clearInterval(timer)
![](https://i-blog.csdnimg.cn/blog_migrate/69ad75e6de886e17fa188d44961a844e.png)
案列:每隔3秒提醒学习,提醒3次后结束
立即执行定时器 setImmediate
setimmediate(回调函数)
process.nextTick(回调函数)
单线程只有一个主程序,而定时器又是比较耗时的操作,所以会把它放在事件队列里,最后执行。
两个立即执行函数的执行顺序也有区别
fs文件系统模块
文件有两种,目录形式 和文件形式
(1)查看文件状态
fs.statSync(文件的路径)
isDirectory() 检查是否为目录,true是目录
isFile() 检查是否为文件,true是文件
![](https://i-blog.csdnimg.cn/blog_migrate/4c4880b094452fe7d56858e2491fa3ad.png)
![](https://i-blog.csdnimg.cn/blog_migrate/66dacd32cf9cf39dcc35a0f2fa3b127e.png)
小技巧,切换到对应的位置后,node后面的内容,文件名可以不写全,之后的按tab键自动补齐
(2)(代码)创建 删除目录
fs.mkdirSync('目录名称'); 创建 不能重复创建,创建一次成功后,再运行会报错,文件已经存在
fs.rmdirSync('目录名称'); 删除目录 删除目录时,目录为空才能成功删除
案列
在主模块(main)中引入一个功能模块file.js,导出一个函数:在3秒钟以后创建1-10,10个目录,在10秒钟以后把10个目录在移除;最后在main.js中调用函数。
![](https://i-blog.csdnimg.cn/blog_migrate/f3e57bb197a147a4929e3040767ebf75.png)
![](https://i-blog.csdnimg.cn/blog_migrate/eaa831de33382244733e63991a0ee038.png)
(3) 读取目录
readdirSync(目录的路径)
readdir(目录的路径,回调函数)
回调函数:用来获取结果
err:可能产生的错误
arr:读取到的内容
注意:两者的区别 sync表示同步,没有这4个单词的表示异步。如果执行过程中有耗时的选择异步,一般情况下选择同步。
sync用变量返回结果,没有他的用回调函数返回结果和提示错误出在哪里。
![](https://i-blog.csdnimg.cn/blog_migrate/afa2da3a3512d7fe9e33551115cf6287.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4bd768c79597acf9352c99ca636dc7df.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d787146ff422369cf815ee9c384604e1.png)
(4)查看状态
fs.stat(目录的路径,回调函数)
(5)覆盖写入
writeFileSync(文件的路径,数据) 同步
writeFile(文件的路径,数据,回调函数)
提示:如果文件不存在,会创建文件然后写入数据,写入时会把原来的内容给覆盖
如果文件已经存在,则覆盖原来的数据写入
(6)追加写入
appendFileSync(文件的路径,数据) 同步
appendFile(文件的路径,数据,回调函数)
提示:如果文件不存在,会创建文件然后写入数据、
如果文件已经存在,会在文件的末尾写入数据
追加写入运行几次,增加几次,但他不会自动换行,需要加上符号\n
但是也会因为编辑器原因而不成功,推荐使用 EditPlus编辑器
(7)读取文件
readFileSync(文件的路径)
readFile(文件的路径,回调函数)
读取的结果为buffer格式,需要转换成字符串。可以用String/toString()
(8)删除文件
unlink(文件的路径,回调函数)
unlinkSync(文件的路径)
(9)检测文件是否存在
existsSync(文件路径) false不存在,true存在
)
(10)拷贝文件
copyFileSync(源文件路径,目标文件路径(加上起文件名字))
copyFile(源文件路径,目标文件路径,回调函数)
)
(11)文件流
createReadStream() 创建可读取的流
createWriteStream() 创建可写入的流
on(事件名称,回调函数) 添加事件,事件名称是固定字符串格式,一旦事件触发自动执行回调函数
pipe() 管道,将读取的流添加到写入流
![](https://i-blog.csdnimg.cn/blog_migrate/c5e35a7ef5a27382fbd07ce338a7264e.png)
同步和异步
同步:在主线程执行,会阻止后续代码的执行,通过返回值来获取结果
异步:在一个独立的线程执行,不会阻止主程序中后续代码的执行,通过回调函数获取结果。异步是独立的,所以不能保证执行结果跟你你写得顺序一样。
注意;node.js是一个单线程,一般情况是按顺序执行。但当涉及了异步时,就是多线程,异步多线程会先放入事件队列中,等主线程执行玩后,在执行。并且如果这个线程报错也不影响主线程的执行,异步报错通过回调函数把结果返回给主线程,无论结果是成功执行还是报错,都要返回给主线程。
异步时,也就是当多个线程进行时,各做各的,谁先完成谁就第一个出现。同步按顺序执行。
注意:这里和定时器 立即执行的知识点不要搞混
http协议
浏览器和web服务器之间的通信协议,浏览器发给web服务器是请求,web服务器给浏览器结果为响应
http协议含有三部分 ,通用头信息(包含响应头信息,请求头信息)响应头信息 请求头信息
通用头信息
Request URL :浏览器向服务器请求的内容
Request Method 请求的方法 get获取/post 投递
Status Code 响应的状态码 (http百度百科里有详细的)
1** 正在响应,还没有结束
2** 成功的响应
4** 客户端请求错误
3** 重定向--跳转到另一个url
5** 服务器端的错误
响应头信息 response
Content-Type 响应的内容类型 html/js/图片...
Location 跳转的URL
请求头信息 request
通用信息里包括了,就不写了
请求主体
可有可无,只有传递数据才会出现,比如表单登录时
http模块 创建自己的服务器
注意:因为你的电脑即当服务器又当客户端,所以容易被电脑的防火墙拦截,所以需要先关闭它。
关闭防火墙
window +r 输入control 打开控制面板后,找到防火墙,关闭
注意:只要修改了就需要保存并重新其启动服务器
ctrl+c 停止服务器端运行
创建web服务器
const app=http.createServer()
设置端口,访问web服务器端口
app.listen(8080);
通过事件接受请求并做出响应
app.on('request',(req,res)=>{
req 请求的对象
req.url 请求的内容 格式为 /login
req.method 请求的方法
res 响应的对象
req.writeHead() 设置响应的状态码和头信息,头信息根据需要写
res.write() 设置响应的内容
res.end() 结束并发送响应
})
//引入http模块
const http=require('http');
//创建web服务器
const app=http.createServer();
//设置端口,用来访问web服务器
//运行了文件,就创造了端口
//在浏览器网页用ip/域名+端口号访问
app.listen(8080);
//接受浏览器的请求并作出响应
//给web服务器端请求的事件
//req请求的对象 res响应的对象
app.on('request',(req,res)=>{
//这句在后台
console.log('有人来啦');
//write 设置响应的内容 显示到浏览器的内容
//现在会乱码
res.write('请问有人在家吗');
//结束并发送响应 响应内容后必须写结束
res.end();
})
//引入http模块
const http=require('http');
//创建web服务器
const app=http.createServer();
//设置端口,用来访问web服务器
//运行了文件,就创造了端口
//在浏览器网页用ip/域名+端口号访问
app.listen(8080);
//接受浏览器的请求并作出响应
//给web服务器端请求的事件
//req请求的对象 res响应的对象
app.on('request',(req,res)=>{
//跳转功能
//设置响应的状态码为302,设置响应属性location
res.writeHead(302,{
Location:'http://www.baidu.com'
});
//结束并发送
res.end();
})
//引入http模块
const http=require('http');
//创建web服务器
const app=http.createServer();
//设置端口,用来访问web服务器
//运行了文件,就创造了端口
//在浏览器网页用ip/域名+端口号访问
app.listen(8080);
//404效果
//接受浏览器的请求并作出响应
//req请求的对象 res响应的对象
app.on('request',(req,res)=>{
//设置响应的状态码为404
//设置响应到浏览器的内容not found
res.writeHead(404);
res.write('not found');
//结束并发送
res.end();
})
//引入http模块
const http=require('http');
//创建web服务器
const app=http.createServer();
//设置端口,用来访问web服务器
//运行了文件,就创造了端口
//在浏览器网页用ip/域名+端口号访问
app.listen(8080);
//404效果
//接受浏览器的请求并作出响应
//req请求的对象 res响应的对象
app.on('request',(req,res)=>{
//获取请求的对象req.url
//console.log输出的值在命令行
console.log(req.url);
//获取请求的方法 req.method
console.log(req.method);
//设置响应的状态码为404
//设置响应到浏览器的内容not found
res.writeHead(404);
res.write('not found');
//结束并发送
res.end();
})
练习:创建web服务器,设置端口,根据浏览器的请求做出响应 当请求的url为index/list/stydy/其他 时,
/index 响应 <h2>这是首页</h2>
/list 响应文件 1.html (读取文件内容,设置为响应的内容)
/study 跳转到 http://www.baidu.com
其他 响应 404 not found
技巧:查看网页源代码,点开之后ctrl+A 就全选了。
//练习:创建web服务器,设置端口,根据浏览器的请求做出响应
//引入http
const http=require('http');
const fs=require('fs');
//创建web服务器
const app=http.createServer();
//设置端口
app.listen(8080);
//浏览器搜索时,应该是 http://localhost:8080/index
//接受请求接受响应
app.on('request',(req,res)=>{
//判断请求的URL,根据请求的url来做出响应
//content-type utf8 解决乱码
if(req.url==='/index'){
res.writeHead(200,{
'Content-Type':'text/html;charset=utf-8'
});
res.write('<h2>这是首页</h2>');
}else if(req.url==='/list'){
//读取文件
let data=fs.readFileSync('./1.html');
//buffer格式
//console.log(data);
//把读取到的文件作为响应的内容,自动转为字符串
res.write(data);
}else if(req.url==='/study'){
res.writeHead(302,{
Location:'http://www.baidu.com'
});
}else{
res.writeHead(404);
res.write('not found');
}
//结束并发送响应
res.end();
});
第三方模块
第三方模块 是其他人写的,目录模块也是它。
包和npm
包:就是一个目录模块,都是第三方模块
npm:用于管理包的工具,包含下载安装、上传、卸载、升级.....
前端开源网站: http://www.npmjs.com
npm命令
npm -v 查看版本号
下载安装
npm install 包名字
完成后,文件夹里会自动多一个node_moudules目录
版本信息 下载地址 在package_lock.json 里 package.json里也有信息可以看
框架
集成了一整套的解决方案 node-modules,框架属于第三方模块
express框架
中文官网:www.expressjs.com.cn
基于node.js平台,快速、开放、极简的web开发框架
下载安装 npm install express
创建web服务器
const express=require('express'); 引入express模块
const app=express(); 创建web服务器
app.listen(8080) 设置端口
//第三方模块 express框架
//包 node-modules
//引入express
const express=require('express');
//检查是否成功引入,成功出来一大堆东西
//console.log(express);
//创建web服务器
//这种方式什么也不写,也会有提示 cannot get / 本质就是404
const app=express();
//设置端口
app.listen(8080);
路由
浏览器端发来请求,web服务器端根据请求的方法和请求的url来作出特定的响应。eg:登录的请求就有登录的路由,注册的请求对应注册的路由.....
路由包含三部分 :请求的方法、请求的url、回调函数
响应对象 res
res.send() 设置响应的内容并发送
res.sendFile() 设置响应的文件并发送,路径需要使用绝对路径 __dirname自动获取绝对路径
res.redirect() 设置响应的重定向并发送
提示:这里不用写end语句了,因为它自身包括了这个功能
响应的内容在网页上看到
请求对象 req
请求的东西在后台
req.url 获取请求的url
req.method 获取请求的方法
req.query 获取查询字符串传递的数据。格式为对象
//第三方模块 express框架
//包 node-modules
//引入express
const express=require('express');
//检查是否成功引入,成功出来一大堆东西
//console.log(express);
//创建web服务器
//这种方式什么也不写,也会有提示 cannot get / 本质就是404
const app=express();
//设置端口
app.listen(8080);
//添加登录的路由
//规定了请求的方法和路由get /login
//只有符合了要求,才会自动执行回调函数
app.get('/login',(req,res)=>{
console.log('有一个登录的请求');
//设置响应的内容,并发送
//响应得到对象 res
//并且不会乱码
res.send('登录成功');
});
练习:添加路由,请求方法get,请求的url /index,响应<h2>这就是首页</h2>
注意:路由是不冲突的,并且不会出现乱码
//第三方模块 express框架
//包 node-modules
//引入express
const express=require('express');
//检查是否成功引入,成功出来一大堆东西
//console.log(express);
//创建web服务器
//这种方式什么也不写,也会有提示 cannot get / 本质就是404
const app=express();
//设置端口
app.listen(8080);
//添加登录的路由
//规定了请求的方法和路由get /login
//只有符合了要求,才会自动执行回调函数
app.get('/login',(req,res)=>{
console.log('有一个登录的请求');
//设置响应的内容,并发送
//响应得到对象 res
//并且不会乱码
res.send('登录成功');
});
//练习:添加路由,请求方法get,请求的url /index
//响应<h2>这就是首页</h2>
//路由是不冲突的
app.get('/index',(req,res)=>{
console.log('有人来啦');
res.send('<h2>这是首页</h2>');
});
//添加路由
//请求方法:get 请求url:/study
app.get('/study',(req,res)=>{
//跳转。重定向到另一个url
res.redirect('http://www.baidu.com');
});
//添加路由/ 跳转到/index
//请求方法:get
//注意/代表浏览器请求后什么也不用写默认为请求/
// /index前面什么也不写,代表在当前url的服务器寻找
app.get('/',(req,res)=>{
res.redirect('/index');
});
//添加路由
//规定 请求方法get 请求路由/list
//规定响应1.html文件
app.get('/list',(req,res)=>{
//注意:./是相对路径
//这里需要绝对路径
//绝对路径找到方法有两种
//一种,直接在位置复制绝对路径
//2种,——dirname 获取绝对路径
//——filename 获取绝对路径加文件名
res.sendFile(__dirname+'/1.html');
});
练习:编写7.js文件,使用express创建web服务器,设置端口;创建路由(get /search 请求方法为get,q请求的路由为/search),响应网页search.html,里面内容为暴富方法,根据表单提交的请求,创建对应的路由(get /mysearch)并响应搜索成功
//js页面内容
//创建服务器
const express=require('express');
const app=express();
app.listen(8080);
//创建路由
app.get('/search',(req,res)=>{
res.sendFile(__dirname+'/search.html');
});
//根据表单提交的请求,创建对应的路由(get /mysearch)
//响应搜索成功
app.get('/mysearch',(req,res)=>{
//获取请求的url,请求的方法,自带
//req.query 直接获取查询字符串传递的数据
//格式为对象
console.log(req.query);
//获取具体的对象
console.log(req.query.kw);
res.send('搜索成功');
})
<!-- 这是html页面内容-->
console.log('暴富方法');<br/>
<!-- form 表单提交,会向服务器端发请求 -->
<!-- method 设置请求的方法 get/post -->
<!-- action 设置请求的url-->
<!-- input name属性 设置输入框的名称,获取用户输入的数据-->
<form method="get" action="/mysearch">
<input type="text" name="kw">
<input type="submit">
</form>
post方法
练习:添加响应登录网页的路由(get /login),响应用户登录网页login.html 页面内容有用户密码提交,点击提交向服务器发送请求(post /mylogin),响应登录成功
//创建服务器
const express=require('express');
//引入查询字符串模块
const querystring=require('querystring');
const app=express();
app.listen(8080);
//添加路由(get /login),响应网页
//这部是把服务器端的东西发送给网页
app.get('/login',(req,res)=>{
res.sendFile(__dirname+'/login.html')
})
//根据表单的请求创建对应的路由(post /mylogin)
//这部是把用户输入的值传给服务器端
app.post('/mylogin',(req,res)=>{
//获取post请求的数据,以流的形式
//一旦有数据流入服务器端,自动执行回调函数
req.on('data',(chunk)=>{
//获取数据,并转为字符串,格式为查询字符串
let str=chunk.toString();
console.log(str);
//将查询字符串解析为对象
//这里需要引入查询字符串模块,但模块的引入要放在开头
let obj=querystring.parse(str);
console.log(obj.kw,obj.pwd);
});
res.send('啦啦啦啦啦啦');
})
console.log('登录成功');
<form method="post" action="/mylogin">
用户:<input type="text" name="kw"></br>
密码:<input type="password" name="pwd"><br/>
<input type="submit" >
</form>
路由传参
在路由那设置形参,用来接受网页的实参
可以多次重新传,不用重新启动服务器
//创建服务器
const express=require('express');
const app=express();
app.listen(8080);
//添加路由 get /package 用户获取包的详情,响应这是包的详情
//:pname 设置形参,用来接受实参
app.get('/package/:pname',(req,res)=>{
//获取路由传参的数据
console.log(req.params);
res.send('这是包的详情')
})
练习:加入购物车的路由(get /shopping),传递商品的编号lid 和数量count,响应添加成功 编号01 数量5
//创建服务器
const express=require('express');
const app=express();
app.listen(8080);
//添加路由 get /package 用户获取包的详情,响应这是包的详情
//:pname 设置形参,用来接受实参
app.get('/package/:pname',(req,res)=>{
//获取路由传参的数据
console.log(req.params);
res.send('这是包的详情')
})
//添加购物车路由 get /shopping
app.get('/shopping/:lid/:count',(req,res)=>{
//响应到服务器
console.log(req.params);
//响应到网页
res.send(`
响应成功
编号:${req.params.lid}
数量:${req.params.count}
`);
})
查询字符串 | /mysearch?kw=手机 | req.query |
post传递 | 流的方式不可见,在form data 可以看见 | req.on('data',(chunk)=>{ chunk,格式为buffer,需要转为字符串、查询字符串,在解析为对象访问 }) |
路由传参 | /package/mysql 红色表示传的真正的值 | 在路由中设置形参接受 红色表示形参,用来接受真正的值,注意多一个实参就要多一个形参 app.get('/package/:pname'(req,res)=>{ req.params 获取路由参数的数据,格式为对象 }) |
路由器
用来管理路由,把同一个模块下的所有路由归纳在一起,可以给同一个模块下的路由添加统一的前缀。这样便于团队协作维护项目,防止url出现冲突
路由器需要用到自定义模块
路由器也是express下的内容,所有需要引入这个模块
创建路由器对象
.....
const r=express.Router();
//往路由器对象添加路由
//导出路由器对象
module.export=r;
在web服务器下挂载
app.use(添加的前缀,引入的路由器) //建议添加的前缀是那个模块名,比如用户模块,就/user
//app.js 主文件
//创建web服务器
const express=require('express');
//引入用户路由器模块user.js
const userRouter=require('./user.js');
//成功打印会出来一堆东西
//console.log(userRouter);
//注意:运行时运行服务器这个主文件 app.js,其他文件都被引入app.js中了
const app=express();
app.listen(8080);
//把路由器挂载到web服务器下
//两个参数
//参数1,给每个路由器添加前缀
//参数2,引入的路由器
//注意访问网页路由时,要加上自己命名的前缀。
app.use('/user',userRouter);
//user.js 用户模块 副文件
//引入express
const express=require('express');
//创建路由器对象
const r=express.Router();
//在路由器下添加路由 get /list 响应用户列表
//注意:现在访问这个路由的话,网页访问应该这样写127.0.0.1:8080/user/list
r.get('/list',(req,res)=>{
res.send('用户列表');
});
//应为是给服务器用,所以需要导出
//它在引入到主文件的过程中,为了与其他模块进行区分,加了前缀/user
//导出路由器对象
module.exports=r;
练习:创建商品路由器product.js,添加今天写得路由,导出路由器,在web服务器挂载,挂载前缀/product
//app.js 主文件
//创建web服务器
const express=require('express');
//引入商品路由器模块user.js
const productRouter=require('./product.js');
//console.log(productRouter);
//注意:运行时的是主文件 app.js,因为其他文件都被引入app.js中了
const app=express();
app.listen(8080);
//把路由器挂载到web服务器下
//添加前缀/product
app.use('/product',productRouter);
//引入express模块
const express=require('express');
//创建路由器对象
const r=express.Router();
//在路由器下添加路由
r.get('/list',(req,res)=>{
res.send('商品列表');
});
//导出·路由器
module.exports=r;
中间件 middleware
处于浏览器和路由之间,用于拦截对路由的请求,最终为路由所服务(就是来判断权限,比如允许你进不进,进入程度,用户管理员等)
中间件分为应用级中间件、路由级中间件、内置中间件、第三方中间件、错误处理中间件
中间件写在路由器前面,服务器后面
所以中间件都要添加到服务器下
应用级中间件
一旦拦截到请求后,会执行一个函数
app.use(要拦截的路由(/url),回调函数) 函数有三个参数
要拦截的url对应路由中的url
//引入express模块
const express=require('express');
//创建web服务器
const app=express();
app.listen(8080);
//添加中间件,拦截对路由的请求
//两个参数
//参数1 要拦截的路由
//参数2 写回调函数,一旦拦截到自动执行
//app.use('/list',()=>{
//在后台服务器显示
//console.log('拦截了对list的请求');
//});
//中间件
//中间件有三个参数
app.use('/list',(req,res,next)=>{
//获取查询字符串传递的数据
console.log(req.query);
//如果用户名不是root,响应请提供管理账户
//否则是管理员,往后继续执行,有可能是下一个中间件或者路由
if(req.query.name!=='root'){
res.send('请提供管理员账户');
}else{
//next表示往后执行它后面的路由,这个必须写
next();
}
});
练习:添加 加入购物车路由(get shopping),传递商品的价格(price);在中间件中将价格打9折;最后在路由中响应商品的价格:xxx
传递数据使用查询字符串
提示:查询字符串是自己直接在网页上写 ?名称=值
//引入express模块
const express=require('express');
//创建web服务器
const app=express();
app.listen(8080);
//商品中间件
app.use('/shopping',(req,res,next)=>{
//打折之前的价格
console.log(req.query);
//获取价格,并打9折
req.query.price*=0.9;
//往后执行
next();
})
//商品路由
app.get('/shopping',(req,res)=>{
//获取查询字符串传递的数据
console.log(req.query);
res.send(`商品的价格为${req.query.price}`);
})
![](https://i-blog.csdnimg.cn/blog_migrate/9eddec5fbcbb4116c361354685ea80a9.png)
中间件因为有拦截的路由名称,所以不用担心写几个会搞混
//引入express模块
const express=require('express');
//创建web服务器
const app=express();
app.listen(8080);
//添加中间件,拦截对路由的请求
//两个参数
//参数1 要拦截的路由
//参数2 写回调函数,一旦拦截到自动执行
//app.use('/list',()=>{
//在后台服务器显示
//console.log('拦截了对list的请求');
//});
//中间件
//中间件有三个参数
app.use('/list',(req,res,next)=>{
//获取查询字符串传递的数据
console.log(req.query);
//如果用户名不是root,响应请提供管理账户
//否则是管理员,往后继续执行,有可能是下一个中间件或者路由
if(req.query.name!=='root'){
res.send('请提供管理员账户');
}else{
//next表示往后执行它后面的路由,这个必须写
next();
}
});
//商品中间件
app.use('/shopping',(req,res,next)=>{
//打折之前的价格
console.log(req.query);
//获取价格,并打9折
req.query.price*=0.9;
//往后执行
next();
})
//在web服务器上添加用户列表路由(get /list), 响应这是用户列表
app.get('/list',(req,res)=>{
res.send('这是用户列表');
});
//商品路由
app.get('/shopping',(req,res)=>{
//获取查询字符串传递的数据
console.log(req.query);
res.send(`商品的价格为${req.query.price}`);
})
路由级中间件
路由器的使用
app.use('要拦截的路由前缀(就是要拦截的那个模块,比如用户模块/user)',拦截模块下的路由(比如用户模块下的用户路由/list))
内置中间件
托管静态资源 (html/css/js/图像....)
浏览器向服务器端请求静态资源,不需要添加路由,让浏览器