fs模块
fs模块可以实现与硬盘的交互
fs模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性, 用来满足用户对文件的操作需求。
fs.readFile()方法,用来读取指定文件中的内容,是异步的 /同步读取fs.readFileSync('path')
fs.writeFile()方法,用来向指定的文件中写入内容,是异步的 /同步写入 fs.writeFileSync('path','内容')
如果要在JavaScript代码中,使用fs模块来操作文件,则需要使用如下的方式先导入它:
const fs = require('fs')
使用fs.readFile( 方法,可以读取指定文件中的内容,语法格式如下:
fs.readFile(path,options,callback)
参数1:必选参数,字符串,表示文件的路径。
参数2:可选参数,表示以什么编码格式来读取文件。
参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果。
同级目录下设置一个1.txt文件,里面输入111
111
//1.导入 fs 模块来操作文件
const fs = require('fs')
//2.调用fs.readFile()方法读取文件
// 参数1:读取文件的存放路径
// 参数2:读取文件时候采用的编码格式,默认utf8
// 参数3:回调函数,拿到读取失败和成功的结果 err dataStr
fs.readFile('./1.txt', 'utf8', function (err, dataStr) {
//若读取成功,err的值为null
//若读取失败,err的值为错误对象,dataStr的值为undefined
console.log(err);
console.log("--------------");
//打印成功的结果
console.log(dataStr);
})
获取成功:err的值为null
![](https://img-blog.csdnimg.cn/img_convert/5de0e6e2ddee8122a3fc9607cc1df34e.png)
若获取失败,手动修改地址为./11.txt 若读取失败,err的值为错误对象,dataStr的值为undefined
![](https://img-blog.csdnimg.cn/img_convert/8002e484a02e1dfce6b647fced2d36b0.png)
案例判断是否读取成功:
const { log } = require('console');
const fs = require('fs')
fs.readFile('./1.txt','utf-8',function (err,dataStr) {
if (err) {
return console.log("读取失败" + err.message);
} else {
return console.log(`读取成功:${dataStr}`);
}
})
![](https://img-blog.csdnimg.cn/img_convert/ee8d8c64bbf43ad269e811986e7d76f5.png)
使用fs.writeFile() 方法,可以向指定的文件中写入内容,语法格式如下:
fs.writeFile(file,data[,options],callback)
参数1:必选参数,需要指定一个文件路径的字符串, 表示文件的存放路径。
参数2:必选参数,表示要写入的内容。
参数3:可选参数,表示以什么格式写入文件内容,默认值是utf8。
参数4:必选参数,文件写入完成后的回调函数。
//1.导入fs文件系统模块
const fs = require('fs')
//2.调用writeFile()方法,来写入文件的内容
// 参数1:文件路径
// 参数2:要写入的内容
// 参数3:回调函数
fs.writeFile('p./2.txt', '222', function (err) {
//若写入成功,err的值为 null,若已有文件路径则修改文件内容,若没有文件则创建一个文件写入
//若写入失败,err的值为一个错误对象
console.log(err);
})
![](https://img-blog.csdnimg.cn/img_convert/6881c04d0c93c452cea8701419c34177.png)
动态路径拼接错误问题
//右键点击左侧想要读取的文件,复制路径,将\变为\\,避免转义符冲突
fs.readFile('F:\\nodejs\\day01\\1.txt','utf8',function (err,dataStr) {
if (err) {
return console.log('读取文件失败'+err.message);
}
console.log(`读取文件成功${dataStr}`);
})
//__dirname表示当前文件所处目录
console.log(__dirname);//F:\nodejs\day01
fs.readFile(__dirname + '/1.txt',function (err,dataStr) {
if (err) {
return console.log('读取文件失败'+err.message);
}
console.log(`读取文件成功:${dataStr}`);
})
__dirname表示当前文件所处目录
console.log(__dirname);
追加写入fs.appendFile()
fs.appendFile(path,追加内容,callback)
path
path模块是Node.js官方提供的、用来处理路径的模块。它提供了一系列的方法和属性, 用来满足用户对路径的处理需求。
path.join()方法,用来将多个路径片段拼接成一个完整的路径字符串
path.basename()方法,用来从路径字符串中,将文件名解析出来
如果要在JavaScript代码中,使用path模块来处理路径,则需要使用如下的方式先导入它:
const path = require('path')
使用path.join()方法,可以把多个路径片段拼接为完整的路径字符串:
//导入path模块
const path = require('path')
// ../会抵消一层路径
const pathStr = path.join('/a','/b/c','../','./d','e')
console.log(pathStr);//\a\b\d\e
const pathStr2 = path.join('/a','/b/c','../../','./d','e')
console.log(pathStr2);//\a\d\e
今后凡是涉及到路径拼接,都要使用path.join()方法进行处理。不要直接使用+进行字符串的拼接。
fs.readFile(path.join(__dirname,'/1.txt'),'utf8',function (err,dataStr) {
if (err) {
return console.log(err.message);
}
console.log(dataStr);
})
使用path.basename()方法,可以获取路径中的最后一部分, 经常通过这个方法获取路径中的文件名,语法格式如下:
path.basename(path[,ext])
path <string> 必选参数,表示个路径的字符串
ext <string>可选参数,表示移除文件扩展名
返回: <string>表示路径中的最后一部分
const path = require('path')
//定义文件的存放路径
const fpath = '/a/b/c/index.html'
//path.basename(),获取文件名
const fullName = path.basename(fpath)
console.log(fullName);//index.html
const nameWithoutExt = path.basename(fpath,'.html')
console.log(nameWithoutExt);//index
使用path.extname()方法,可以获取路径中的扩展名部分,语法格式如下:
path.extname(path)
path <string>必选参数,表示个路径的字符串
const path = require('path')
const fpath = '/a/b/c/index.html'
//获取文件扩展名
const fext = path.extname(fpath)
console.log(fext);//.html
http
http模块是Node.js官方提供的、用来创建web服务器的模块。通过http模块提供的http.createServer()方法,就能方便的把一台普通的电脑,变成一台Web服务器,从而对外提供Web资源服务。
如果要希望使用http模块创建Web服务器,则需要先导入它:
const http = require('http')
服务器和普通电脑的区别在于,服务器上安装了web服务器软件,例如: IIS、 Apache 等。通过安装这些服务器软件,就能把一台普通的电脑变成一台web服务器。
在Node.js中,我们不需要使用IIS、Apache 等这些第三方web服务器软件。因为我们可以基于Node.js提供的http模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供web服务。
ip地址
IP地址就是互联网上每台计算机的唯一地址
IP地址的格式:通常用“点分十进制"表示成(a.b.c.d) 的形式,其中,a,b,c,d 都是0~255之间的十进制整数。例如:用点分十进表示的IP地址(192.168.1.1)
①互联网中每台Web服务器,都有自己的IP地址,例如:大家可以在Windows的终端中运行ping www.baidu.com命令,即可查看到百度服务器的IP地址。
②在开发期间,自己的电脑既是一台服务器, 也是一个客户端, 为了方便测试,可以在自己的浏览器中输入127.0.0.1这个IP地址,就能把自己的电脑当做一台服务器进行访问了 。(只能自己访问)
域名和域名服务器
尽管IP地址能够唯一地标记网络上的计算机,但IP地址是一长串数字, 不直观,而且不便于记忆,于是人们又发明了另一套字符型的地址方案,即所谓的域名(Domain Name)地址。
IP地址和域名是一一对应的关系, 这份对应关系存放在一种叫做域名服务器(DNS, Domain name server)的电脑中。使用者只需通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供IP地址和域名之间的转换服务的服务器。
注意:在开发测试期间,127.0.0.1 对应的域名是localhost,它们都代表我们自己的这台电脑,在使用效果上没有任何区别。
端口号
在一台电脑中,可以运行成百上千个web服务。每个web服务都对应一个唯一的端口号。 客户端发送过来的网络请求,通过端口号,可以被准确地交给对应的web服务进行处理。
![](https://img-blog.csdnimg.cn/img_convert/1648796bd64275ae3d1f180cc654a144.png)
注意:
每个端口号不能同时被多个web服务占用。
在实际应用中,http的URL中的80端口可以被省略。https的默认端口号是443
使用http创建web服务器
1.创建web服务器的基本步骤
①导入http模块
②创建web服务器实例
③为服务器实例绑定request事件,监听客户端的请求
④启动服务器
//1.引入http模块
const http = require('http')
//2.创建web服务
http.createServer((req,res) => {
//req 前端发送过来的数据
//res 服务器响应给前端的数据
//设置响应头
//content-type:数据类型
//text/plain:文本类型
//text/html: 可解析标签
//charset=utf-8:以utf-8来解析字符
res.setHeader('content-type','text/html;charset=utf-8')
//res.write 表示给前端返回的数据内容
res.write('<h1>首页</h1>')
// console.log(res);
res.write('111111')
//结束响应 res.end()
res.end("22222")//结束响应,可传入数据
}).listen("8080",() => {
console.log("web服务器在8080端口启动");
})
req请求对象
const http = require('http')
const server = http.createServer()
server.on("request",(req,res) => {
// req是请求对象,包含了与客户端相关的数据和属性
const url = req.url//路径
//req.method 是客户端请求类型
const method = req.method
const str = `Your request url is ${url},and request method is ${method}`
console.log(str);
})
server.listen(80,()=> {
console.log("server running at http://127.0.0.1");
})
![](https://img-blog.csdnimg.cn/img_convert/d359d5b84401cb54d7ac5902c75601d7.png)
req练习
const http = require('http')
const server = http.createServer((req, res) => {
//获取请求的方法
let {method} = req;
//获取请求的url路径
let {pathname} = new URL(req.url,'http://127.0.0.1');
console.log(method,pathname);
res.setHeader("content-type","text/html;charset=utf-8")
//判断
if (method === 'GET' && pathname === '/login') {
res.end('登录页面')
} else if (method === 'GET' && pathname === '/reg') {
res.end('注册页面')
}
})
server.listen(9000, () => {
console.log("server running at http://127.0.0.1:9000");
})
总结:
1.每次修改了代码都需要重新启动一次服务器,否则代码修改无效。
2.res.end方法只能执行一次
3.res.end()后面的代码不会被执行
4.没有结束响应即没有执行res.end()会一直占用资源,一直跟服务端建立连接
![](https://img-blog.csdnimg.cn/img_convert/47be71db610c0de7546ed29ad424e112.png)
5.所以要给其他没有的路由响应一个res.end('404 Not Found'),防止一直占用资源
//判断
if (method === 'GET' && pathname === '/login') {
res.end('登录页面')
} else if (method === 'GET' && pathname === '/reg') {
res.end('注册页面')
} else {
res.end('Not Found')
}
res响应对象
设置响应头
当调用res.end()方法,向客户端发送中文内容的时候,会出现乱码问题,此时,需要手动设置内容的编码
res.setHeader("content-type", "text/html;charset=utf-8")
设置响应状态码
设置响应状态码,默认为200
//修改响应状态码为203
res.statusCode = 203;
设置响应体
res.write('any content')
res.write('any content')
res.write('any content') //不覆盖
res.end('response')//结束响应,只能执行一个end方法,可以写可不写参数
![](https://img-blog.csdnimg.cn/img_convert/6dbb4de0211efd83e9a01d8356c5c7fb.png)
const http = require('http')
const server = http.createServer()
server.on("request",(req,res) => {
const str = `您请求的url地址是${req.url},请求的method 类型为${req.method}`
// 解决中文乱码
res.setHeader("content-type","text/html;charset=utf-8")
res.end(str)
})
server.listen("80",() => {
console.log("server running at http://127.0.0.1");
})
![](https://img-blog.csdnimg.cn/img_convert/2076f825c72a580b8989f08f7157cbdc.png)
decodeURIComponent(req.url)//将乱码转换为正常码
decodeURIComponent(req.url)
静态资源服务
静态资源是指内容长时间不发生改变的资源,例如图片,视频,CSS 文件,JS文件,HTML文件,字体文件等
综合案例:通过nodejs创建web服务器,将本地整个项目响应给客户端
const fs = require('fs')
const path = require('path')
const http = require('http')
//创建web服务
let app = http.createServer((req, res) => {
// console.log(req.url);
if (req.url === "/") {
res.setHeader("content-type", "text/html;charset=utf-8")
fs.readFile(path.join(__dirname, './byte-dance/index.html'), 'utf-8', (err, dataStr) => {
if (!err) {
res.end(dataStr)
}
})
} else if (decodeURIComponent(req.url)) {
fs.readFile(path.join(__dirname, `./byte-dance${decodeURIComponent(req.url)}`), (err, dataStr) => {
if (!err) res.end(dataStr)
})
}
})
app.listen("8080",() => {
console.log("服务器启动在 http://127.0.0.1:8080");
})
网页资源加载:先index.html ,在html中,link、pic、src、js的请求是会并行的,不是要等到前面的先加载完再加载后面的。
根据请求url路径区分请求的内容
HTTP服务在哪个文件夹中寻找静态资源,那个文件夹就是静态资源目录,也称之为网站根目录
动态资源服务
动态资源是指内容经常更新的资源,例如百度首页,网易首页,京东搜索列表页面等
url绝对路径和相对路径
绝对路径
![](https://img-blog.csdnimg.cn/img_convert/5e66f8c0c36ac3aaa6890f65f37ddf72.png)
相对路径
相对路径在发送请求时,需要与当前页面URL路径进行计算,得到完整URL后,再发送请求,学习阶段用的较多
例如当前网页url为http://www.atguigu.com/course/h5.html
![](https://img-blog.csdnimg.cn/img_convert/8f6031952c437500a77ee975c718fc83.png)
设置资源类型mime类型
媒体类型(mime)是一种标准,用来表示文档、文件的性质和格式
HTTP服务可以设置响应头Content-Type来表明响应体的MIME类型,浏览器会根据该类型决定如何处理资源
常见文件对应的mime类型
html: 'text/html'
CSS: 'text/css'
js: 'text/javascript'
png: 'image/png
jpg: 'image/jpeg'
gif: 'image/gif'
mp4: 'video/mp4'
mp3: 'audio/mpeg'
json: 'application/json'
浏览器会根据加载的类型自动判断并解析资源
GET请求与POST请求
![](https://img-blog.csdnimg.cn/img_convert/c0e50d38fc8f7d14f1f2539cc21206d2.png)
![](https://img-blog.csdnimg.cn/img_convert/816e4fc36d831fcb76081388038e4835.png)
两者的区别
GET和POST是HTTP协议请求的两种方式,主要有如下几个区别
1.作用。GET主要用来获取数据,POST 主要用来提交数据
2.参数位置。GET 带参数请求是将参数缀到URL之后,POST带参数请求是将参数放到请求体中
3. 安全性。POST请求相对GET安全一些,因为在浏览器中参数会暴露在地址栏
4. GET 请求大小有限制,一般为2K,而POST请求则没有大小限制
模块化
前言
创建01.js and 02.js 分别引入test.html
//01.js
let a = 10
//02.js
let a = 20
<script src="./01.js"></script>
<script src="./02.js"></script>
<script>
console.log(a);
</script>
![](https://img-blog.csdnimg.cn/img_convert/35c893d8d21d2c55f89422aa0f18de01.png)
没有模块化,数据不能私有,共同开发时会有变量污染
概念
将一个复杂的程序文件依据一定的规则拆分成多个文件的过程称之为模块化,其中拆分出的每一个文件就是一个模块,模块的内部数据是私有的,不过模块可以暴露内部数据供其他模块使用。
把代码进行模块化拆分的好处:
①提高了代码的复用性
②提高了代码的可维护性
③可以实现按需加载
Node.js中模块的分类
Node.js中根据模块来源的不同,将模块分为了3大类,分别是:
●内置模块(内置模块是由Node.js官方提供的,例如fs、 path、 http等)
●自定义模块(用户创建的每个js文件,都是自定义模块)
●第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)
加载模块/导入模块
使用强大的require()方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用。
导入自定义模块要加相对路径,不能省略./or../
.js/.json后缀名可省略,执行被加载的文件中的代码,返回{}
//加载自定义模块
const m1 = require('./04-http.js')
console.log(m1);//{} 并且执行./04-http中的代码
如果导入的路径是个文件夹,则会首先检测该文件夹下package. json文件中main属性对应的文件,
如果存在则导入,反之如果文件不存在会报错。
如果main属性不存在,或者package.json不存在,则会尝试导入文件夹下的index.js 和index. json ,
如果还是没找到,就会报错
模块作用域
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。
const username = "张三"
function sayHello() {
console.log("hello,my name is"+ username);
}
const custom = require('./06-模块作用域')
console.log(custom);//{}
![](https://img-blog.csdnimg.cn/img_convert/203ae6781fe7946adf6bbf0db9aa0295.png)
module对象
在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息
console.log(module);
![](https://img-blog.csdnimg.cn/img_convert/eb703379857184cfb9d1b0f1b0b336d0.png)
module.exports 将模块内的成员共享出去
外界用require()方法导入自定义模块时,得到的就是module.exports所指向的对象。
const username = "张三"
function sayHello() {
console.log("hello,my name is"+ username);
}
module.exports.username = "张三"
module.exports.sayHello = function () {
console.log('hello');
}
const m1 = require('./06-模块作用域')
console.log(m1);//{}
const m2 = require('./07-exports')
console.log(m2);//{ username: '张三', sayHello: [Function (anonymous)] }
exports对象
由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码, Node提供了exports对象。默认情况下,exports 和module.exports指向同一个对象。最终共享的结果,还是module.exports指向的对象为准。
console.log(exports === module.exports);//true
Node.js中的模块化规范
Node.js遵循了CommonJS模块化规范,CommonJS 规定了模块的特性和各模块之间如何相互依赖。
CommonJS规定:
①每个模块内部,module 变量代表当前模块。
②module变量是一个对象, 它的exports属性(即module.exports)是对外的接口。
③加载某个模块,其实是加载该模块的module.exports属性。require0 方法用于加载模块。
npm与包
Node.js中的第三方模块又叫做包。
不同于Node.js中的内置模块与自定义模块,包是由第三方个人或团队开发出来的,免费供所有人使用。
从哪里下载包?
从https://www.npmjs.com/网站上搜索自己所需要的包
从https://registry.npmjs.org/服务器上下载自己需要的包
这个包管理工具的名字叫做Node Package Manager (简称npm包管理工具),这个包管理工具随着Node.js的安装包一起被安装到了用户的电脑上。
大家可以在终端中执行npm -V命令,来查看自己电脑上所安装的npm包管理工具的版本号:
![](https://img-blog.csdnimg.cn/img_convert/b75eba0b3262da3d7e43498b4061cd46.png)
格式化时间的高级做法
①使用npm包管理工具,在项目中安装格式化时间的包moment
②使用require()导入格式化时间的包
③参考moment的官方API文档对时间进行格式化
1.在项目中安装包的命令
npm install 包名 / npm i 包名
![](https://img-blog.csdnimg.cn/img_convert/62836e09ec812a4de1506642f1dde1f1.png)
2.导入包
const moment = require('moment')
3.参考moment的官方API文档使用包
const moment = require('moment')
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt);//2023-03-09 09:54:31
包
初次装包完成后,在项目文件夹下多一个叫做 node._modules的文件夹和package-lock.json的配置文件。
其中:
node_modules 文件夹用来存放所有已安装到项目中的包。require() 导入第三方包时,就是从这个目录中查找并加载包。
package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。
默认情况下,使用npm install命令安装包的时候,会自动安装最新版本的包。如果需要安装指定版本的包,可以在包名之后,通过@符号指定具体的版本,例如:
npm i moment@2.22.2
多人协作开发时:共享时剔除node_modules
在项目根目录中,创建一个叫做 package.json的配置文件,即可用来记录项目中安装了哪些包。从而方便剔除node_ modules目录之后,在团队成员之间共享项目的源代码。
今后在项目开发中,一定要把 node_modules文件夹,添加到.gitignore 忽略文件中。
有package.json,重新下载如下
npm i
npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json 这个包管理
npm init -y
package.json文件中,有一个dependencies节点,专门]用来记录您使用npm install命令安装了哪些包。
![](https://img-blog.csdnimg.cn/img_convert/48eee95cf78e42e45a74ec07deb60119.png)
当我们拿到一个剔除了node. modules的项目之后,需要先把所有的包下载到项目中,才能将项目运行起来。
一次性下载dependencies节点里所有包
npm i / npm install
卸载包
npm uninstall 包名
devDependencies节点
如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中。与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies节点中。
npm i 包名 -D
快速下载包
![](https://img-blog.csdnimg.cn/img_convert/57ff205bef1aad98a65961d5460993f5.png)
包的分类
项目包
那些被安装到项目的node_modules目录中的包,都是项目包。
项目包又分为两类,分别是:
●开发依赖包(被记录到devDependencies节点中的包,只在开发期间会用到)
●核心依赖包(被记录到dependencies节点中的包,在开发期间和项目上线之后都会用到)
//下载生产依赖包
npm i 包名 / npm i -S 包名
//下载开发依赖
npm i -D 包名
全局包
在执行npm install命令时,如果提供了-g参数,则会把包安装为全局包。
npm i -g 包名
查看全局包的下载路径
npm list -g
配置命令别名
配置package.json中的scripts属性
"scripts": {
"server": "node server.js",
"start": "node index.js"
}
配置完成后,可以使用别名执行命令
npm run 有自动向上级目录查找的特性,不必重复安装module
npm run server
//start别名比较特别,使用时可以省略run
npm start
模块的加载机制
模块在第一次加载后会被缓存。这也意味着多 次调用require()不会导致模块的代码被执行多次。
内置模块是由Node.js官方提供的模块,内置模块的加载优先级最高。
例如,require('fs') 始终返回内置的fs模块,即使在node_ modules目录下有名字相同的包也叫做fs。
使用require0加载自定义模块时,必须指定以./或../开头的路径标识符。在加载自定义模块时,如果没有指定./或../这样的路径标识符,则node会把它当作内置模块或第三方模块进行加载。
同时,在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:
①按照确切的文件名进行加载
②补全.js扩展名进行加载
③补全.json扩展名进行加载
④补全.node扩展名进行加载
⑤加载失败,终端报错
Express
官方给出的概念: Express 是基于Node.js平台,快速、开放、极简的Web开发框架。
通俗的理解: Express 的作用和Node.js内置的http模块类似,是专门用来创建Web服务器的。
Express的本质:就是一个npm上的第三方包,提供了快速创建Web服务器的便捷方法。
Express的中文官网: http://www.expressjs.com.cn/
安装
npm i express@4.17.1
使用express创建基本web服务器
//使用express创建基本web服务器
const express = require('express')
//创建 web服务器
const app = express()
//启动web服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1');
})
监听GET请求
通过app.get()方法,可以监听客户端的GET请求
监听POST请求
通过app.post()方法,可以监听客户端的POST请求
把内容响应给客户端
通过res.send()方法,可以把处理好的内容,发送给客户端
//使用express创建基本web服务器
const express = require('express')
//创建 web服务器
const app = express()
app.get('/user', (req, res) => {
//调用express提供的res.send()方法,向客户端响应一个JSON对象
res.send({ name: "zs", age: 18, gender: "male" })
})
app.post("/user",(req,res)=> {
//调用express提供的res.send()方法,向客户端响应一个文本字符串
res.send("请求成功")
})
//启动web服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
获取URL中携带的查询参数(?后面的数据)
通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数
默认为一个空对象
app.get("/", (req, res) => {
//通过req.query可以获取到客户端发送过来的 查询参数,默认:req.query是一个空对象
console.log(req.query);//{}
res.send(req.query)//{}
})
http://127.0.0.1/?name=zs&age=20
![](https://img-blog.csdnimg.cn/img_convert/27bfe0a3b672481637ba9a84a74cf193.png)
获取URL中的动态参数
通过req.params对象,可以访问到URL中,通过:匹配到的动态参数:
app.get('/user/:id',(req,res) => {//id只是一个名字,可任意更改
//req.params 是动态匹配到的url参数,默认也是一个空对象
console.log(req.params);
res.send(req.params)
})
![](https://img-blog.csdnimg.cn/img_convert/9f49ed3131a129c151b8aece778063eb.png)
可匹配多个动态参数
app.get('/user/:id/:name',(req,res) => {
//req.params 是动态匹配到的url参数,默认也是一个空对象
console.log(req.params);
res.send(req.params)
})
![](https://img-blog.csdnimg.cn/img_convert/9d40f6970019061e148b897363592725.png)
托管静态资源
express.static()
express提供了一个非常好用的函数,叫做express.static(),通过它,我们可以非常方便地创建一个静态资源服务器 .
例如,通过如下代码就可以将public目录下的图片、CSS 文件、JavaScript 文件对外开放访问了:
app.use(express.static('public'))
![](https://img-blog.csdnimg.cn/img_convert/5fe980e48a551d439767ebea09e978ec.png)
即"public"文件名不会出现在URL中
const express = require('express')
//创建web服务器
const app = express()
//调用express.static()方法,快速的对外提供静态资源
app.use(express.static('../day02/byte-dance'))
//启动服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
![](https://img-blog.csdnimg.cn/img_convert/d0cabec2c59fdba3bf3372a56dafb820.png)
![](https://img-blog.csdnimg.cn/img_convert/51a1bd88499eeeadb69e613717eed2e4.png)
2.托管多个静态资源目录
如果要托管多个静态资源目录,请多次调用express.static()函数:
访问静态资源文件时,express static0函数会根据目录的添加顺序查找所需的文件。
3.挂载路径前缀
如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下的方式:
app.use('/public',express.static('public'))
![](https://img-blog.csdnimg.cn/img_convert/39c1301057f66575c6a0c9cde661ea30.png)
即"public"文件名会出现在URL中
const express = require('express')
//创建web服务器
const app = express()
//调用express.static()方法,快速的对外提供静态资源
app.use('/abc',express.static('../day02/byte-dance'))
//启动服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
打开页面后手动添加/abc
![](https://img-blog.csdnimg.cn/img_convert/fbeb315f504d7f870a469ce454e3728d.png)
![](https://img-blog.csdnimg.cn/img_convert/b1c872e1948c4beae0964459f25ed3ec.png)
![](https://img-blog.csdnimg.cn/img_convert/991074e7df64c5b38f535ace7930812e.png)
nodemon
在编写调试Node,js项目的时候,如果修改了项目的代码,则需要频繁的手动close掉,然后再重新启动,非常繁琐。
现在,我们可以使用nodemon (https://www.npmjs.com/package/nodemon) 这个工具, 它能够监听项目文件的变动,当代码被修改后,nodemon会自动帮我们重启项目,极大方便了开发和调试。
npm install -g nodemon
现在,我们可以将node命令替换为nodemon命令,使用nodemon app.js来启动项目。
npx nodemon 文件路径
路由
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
Express中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式如下:
app.请求类型(path,处理函数)
路由的匹配过程
每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。
在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的URL同时匹配成功,则Express会将这次请求,转交给对应的function函数进行处理。
按顺序匹配,若之前已经匹配成功,则后面不会重复匹配。
最简单的路由使用
const express = require('express')
const app = express()
app.get('/',(req,res)=>{res.send('get request')})
app.post('/',(req,res)=>{res.send('post request')})
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
模块化路由
为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。
将路由抽离为单独模块的步骤如下:
①创建路由模块对应的js文件
②调用express.Router(函数创建路由对象
③向路由对象上挂载具体的路由
④使用module.exports向外共享路由对象
⑤使用app.use0函数注册路由模块
①~④
//使用express创建基本web服务器
const express = require('express')
//创建路由对象
const router = express.Router()
//挂载具体路由
router.get('/user/list',(req,res)=>{
res.send('Get user list')
})
router.post('/user/add',(req,res)=>{
res.send('Post user add')
})
//向外导出路由对象
module.exports = router
⑤
const express = require('express')
const app = express()
//导入路由模块
const router = require('./04-创建路由模块Router.js')
//注册路由模块
app.use(router)
// app.use()是来注册全局中间件
app.listen(80, () => {
console.log('http://127.0.0.1');
})
为路由模块添加前缀
const express = require('express')
const app = express()
//导入路由模块
const router = require('./04-创建路由模块Router.js')
//注册路由模块
app.use('/123',router)
// app.use()是来注册全局中间件
app.listen(80, () => {
console.log('http://127.0.0.1');
})
![](https://img-blog.csdnimg.cn/img_convert/9f3ecab297eeec33b1b2af6b84d90e41.png)
中间件
中间件(Middleware ),特指业务流程的中间处理环节。
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
Express的中间件,本质上就是一个function处理函数
(req,res,next))=>{next()}
中间件函数的形参列表中,必须包含next参数。而路由处理函数中只包含req和res。
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一一个中间件或路由。
const express = require('express')
const app = express()
//定义一个中间件
const mw = function (req, res, next) {
console.log('这是最简单的中间件函数');
//必须有next()
next()
}
app.listen(80, () => {
console.log('http://127.0.0.1');
})
全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。
通过调用app.use(中间件函数),即可定义一个全局生效的中间件,示例代码如下:
const express = require('express')
const app = express()
//定义一个中间件
const mw = function (req, res, next) {
console.log('这是最简单的中间件函数');
//必须有next()
next()
}
//将mw注册为全局生效的中间件
app.use(mw)
app.get('/', (req, res) => {
res.send('hello')
})
app.listen(80, () => {
console.log('http://127.0.0.1');
})
4.中间件的作用
多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
5.定义多个全局中间件
可以使用app.use()连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用,示例代码如下:
const express = require('express')
const app = express()
//定义第多个全局中间件
app.use((req, res, next) => {
console.log("调用了第一个全局中间件");
next()
})
app.use((req, res, next) => {
console.log("调用了第二个全局中间件");
next()
})
app.use((req, res, next) => {
console.log("调用了第三个全局中间件");
next()
})
app.get('/', (req, res) => {
res.send('hello~')
})
app.listen(80, () => {
console.log('http://127.0.0.1');
})
![](https://img-blog.csdnimg.cn/img_convert/964e908f89c256ceaf5750b9cb541760.png)
不使用app.use0定义的中间件,叫做局部生效的中间件
const express = require('express')
//局部生效的中间件
const app = express()
const wm = (req, res, next) => {
console.log("局部中间件");
next()
}
app.get('/', wm, (req, res) => {
res.send('hello~')
})
app.listen(80, () => {
console.log('http://127.0.0.1');
})
了解中间件的5个使用注意事项
①一定要在路由之前注册中间件
②客户端发送过来的请求,可以连续调用多个中间件进行处理
③执行完中间件的业务代码之后,不要忘记调用next()函数
④为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
⑤连续调用多个中间件时,多个中间件之间,共享req和res对象
错误级别的中间件
错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err, req, res, next)。