为什么要学习nodejs
-
原因
因为这是一门后台开发语言,用js来写得后台语言,使用ecma规范,前端人员学习起来不用再从基础得语法知识学起比较快上手,当代前端也需要了解后端开发是在什么,甚至有一些原本由后端处理得工作现在已经是前端在做了,所以前端也需要懂得后端知识(更直接说也是为了升职加薪 哈哈)
-
node搭建中间层
https://www.weipxiu.com/3679.html 这片文章有解释。 也是我学习node的目的
-
规范
在node.js中都是使用模块化开发,一个js文件就是一个模块,这是跟js语言本身得缺陷有关,js是一门开放语言,存在两个问题,命名冲突和文件依赖。而代码最理想得方式就是半开放式,就是需要在别得地方用到得代码功能暴露出去,其他得不暴露。这就是模块化开发
-
暴露引入
-
分别暴露方式(把要暴露得东西当成exports对象得属性暴露出去,通过require引入)
- 暴露 exports.xxx = xxx
- 引入 xxx = require('/path')
-
默认暴露方法
- 暴露 module.exports.xxx = xxx
注意:这两种方法暴露出去得东西都会在添加在一个对象中,也就是说引入时引入得的是一个对象,数据都在这个对象上面。但是,当exports和module.exports 暴露的时候指向的不是一个对象的话,会以module.exports暴露的为准。
-
nodejs就是基于模块化开发的形式,一下介绍nodejs中的模块之间的区别
-
系统模块
node环境提供的api就是系统模块,比如读取文件api,写入文件api,创建文件api等
-
fs系统文件操作模块
- fs.readFile('文件路径/文件名',‘要写入的内容’,callback) 读取文件内容方法
- fs.writeFIle('文件路径/文件名',‘要写入的内容’,callback) 写入文件方法
- callback的作用就是等方法运行完了将执行结果通过形参是的方式传递给回调函数让开发者知道执行结果
- callback异步都会用,因为异步的行为执行需要时间 无法直接拿到返回值,所以需要等执行完成由callback来接收结果
- 在node中callback都是第个参数是err第二个是别的。callback接受两个参数 第一个是err错误日志 第二个是doc内容
-
path系统路径模块api
注意:在window中系统路径只有/ 在Linux中系统路径由 / 和 \ 两种,path方法会判断当前操作系统,然后使用不同的路径拼接符进行拼接,这也可以使我们的代码更通用- path.join('路径','路径','路径',。。。) 路径拼接
-
相对路径和绝对路径
- 相对路径: 在文件中写是相对于自身,在命令行工具中相对于当前工作目录,这样写不安全。使用相对路径写的路径地址在命令行工具中只能在当前目录下才可以运行,其他目录下报错,绝对路径就不会由这种情况
- 绝对路径: __dirname 这个变量可以直接拿到当前文件目录,再拼接上文件名 这样就是一个绝对路径地址,比较安全。
- 例子:一般写法都是 这样 path.join(__dirname,'文件名') 通过path.join这个方法拿到完整的文件路径
- 注意: require方法相对的就是当前文件 所以require方法可以放心的用相对路径
-
-
第三方模块概念
一般第三方模块是别人写好的,具有特定功能的,文件比较大,由多个文件组成。
通常js以两种形式存在
- js形式:通常是封装了一些功能,向外提供api接口,供其他开发者使用,
- 以命令行工具形式存在: 提供命令给工具中的命令,辅助开发
-
第三方模块(nodejs使用):
- nodemon:可以让代码自动保存运行,有点类似页面热加载时时更新
- 下载 npm install nodemon
- 运行 nodemon 文件名
- nrm: npm registry manager 切换下载地址工具(就是切换到国内镜像)
- 下载 npm install nrm -g
- 查看可用的下载地址服务器 nrm ls
- 使用下载地址 nrm use 下载地址名称
- mime :这个模块可以根据请求地址获取要请求的参数类型,要用getType()方法
- 下载 npm install mime
- 使用 mime.getType(请求地址)
- 使用场景: 当返回响应的时候不止要返回数据,还要返回数据类型,请求状态码,如果不指定返回数据类型的话可能在低版本浏览器中出错
- util模块
- util模块下有一个promisify方法,这个方法可以包装nodejs的api让他返回的值是promise对象,方便配合async await使用
- 使用:
const fs = require('fs') //promisify是用来改造nodejs异步的api的,让他返回的是一个promise对象,方便进行异步操作 const promisify = require('util').promisify // 改造fs.readFile方法 返回一个promise对象 const readFile = promisify(fs.readFile) async function run () { //改造后的方法读取文件,不用再写回调函数了, //而且他是一个promise对象.await可以直接拿到它resolve的值 let r1 = await readFile('./1.txt','utf8') let r2 = await readFile('./2.txt','utf8') let r3 = await readFile('./3.txt','utf8') console.log(r1) //1 console.log(r2) //2 console.log(r3) //3 } run(); // 1 2 3
- nodemon:可以让代码自动保存运行,有点类似页面热加载时时更新
- mongoose: nodejs要通过这个模块才可以操作mongodb数据库
-
第三方模块(gulp使用)
-
gulp
处理工作的行为都要放在.pipe()中处理 比如dest()方法 比如调用插件方法的时候
- 使用步骤
- npm install gulp 下载
- 在项目根目录下创建gulpfile.js文件
- 创建src文件夹把所有源代码文件放进去,创建dist文件夹用来存放压缩后的文件
- 在gulpfile.js文件中编写任务规则
- 在命令行工具中执行gulp
- gulp提供的方法
- gulp.src() 获取任务处理的文件
- gulp.dest() 输出文件
- gulp.task() 建立gulp任务
- gulp.watch() 监视文件的变化
- gulp第三方插件(想要实现压缩等功能都得通过插件做,gulp本身只提过了几个方法)
- gulp-htmlmin 压缩html代码 具体去npm上看文档
- gulp-file-include 提取html中的公共代码部分
- 1下载
- 2加括号调用
- 3使用@@include把拆分出去的代码引入回来 (在同类代码文件中)
- gulp-csso 压缩css代码
- gulp-less 压缩less代码
- gulp-babel 转换es6代码为es5代码
- gulp-uglify 压缩js代码
- 使用步骤
-
gulp构建任务 (如果任务名叫defualt 那么执行时直接gulp就可以了)
所谓构建就是执行一个命令把写好的所有命令都执行,gulp3和gulp4构建方法不一样,建议百度,我这里使用的是gulp4- 创建一个任务
- 使用gulp.series 或者gulp.parallel 进行构建
gulp.series方式: gulp.task('my-task',gulp.series('a','b','c',async () => { // a b c参数就是你写好的任务 比如压缩html css js或者图片什么的哪些任务 })); gulp.task('my-task',gulp.series('a',gulp.parallel('style','script','image'),'b','c', async () => { // a b c参数就是你写好的任务 比如压缩html css js或者图片什么的哪些任务 })); gulp.parallel方式: gulp.task('build',gulp.parallel('style','script','images',async () => { // a b c参数就是你写好的任务 比如压缩html css js或者图片什么的哪些任务 }));
-
服务器基本知识
- url
- url的组成: 协议://域名或者ip:端口/资源所在标识符 例:http://www.baidu.com:8080/tieba?xxx=yyy 端口号默认是8080;
- 协议 http https
http: 超文本传输协议,文本中不止可以有文字还可以有图片音频视频等
https: 比http更安全的协议,
- 协议 http https
- url的组成: 协议://域名或者ip:端口/资源所在标识符 例:http://www.baidu.com:8080/tieba?xxx=yyy 端口号默认是8080;
- 本机ip和域名
本机ip: 127.0.0.1
本机域名:localhost:端口号
- url
-
创建启动一个服务(也是创建服务器)
三大步:
- 创建服务器对象 (这一步需要引入系统模块http,使用http.createServer()方法创建服务器对象)
- 处理客户端请求,返回响应 (这一步需要使用 服务器对象.on('request',(req,res) => {})处理请求,服务器对象.end(‘相应内容’)返回响应)
- 监听一个端口号 (使用服务器对象.listen(端口号))
- 运行启动服务 (nodemon 文件名 或者nodejs 文件名)
* 创建服务 的步骤
* 1 需要引入使用nodejs中提供的系统模块 http,并且创建服务器对象 需要调用http模块的createServer()方法
* 2 处理请求 返回相应
* 3 监听端口号
* 4 打印运行
*
* 访问方法: 通过localhost:端口号
*/
//引入Http模块
const http = require('http')
//创建一个服务器对象
const app = http.createServer()
//服务器对象.on 第一个参数用来绑定处理客户端的请求的时间,通过第二个参数回调函数返回响应
app.on('request',(req,res) => {
//设置返回的响应格式为utf-8,Http状态码是200 不写这个会乱码
res.writeHead(200, { 'Content-Type': 'text/plain;charset=utf-8' });
//res.end 用来返回响应的
res.end('<h2>这是服务器返回的一串字符</h2>')
})
// 监听端口号
app.listen(3000)
console.log('服务器启动成功')
-
协议 http
http超文本传输协议,规定了浏览器和服务器之间的通信规则,他们之中有一些概念看下方
- 报文: 报文就是客户端和服务器请求中的数据块就叫报文,分为请求报文和响应报文
请求报文:客户端向服务器发请求时携带的数据块
响应报文:服务器响应返回给客户端的数据块
- 报文: 报文就是客户端和服务器请求中的数据块就叫报文,分为请求报文和响应报文
-
处理请求(get,post)
-
req.url请求地址
-
req.header请求头请求报文信息
-
req.methods请求方法
-
get请求
- get请求中数据传输是query形式的会暴露在地址栏上,这样就可以使用系统模块url进行一些处理
- 系统内置模块 url.parse方法可以把req.url里的所有参数转换成一个对象,方便查看,还可以传第二个参数让query参数变成一个对象方便我们直接拿到使用,
- res.writeHead() 这个方法可以设置响应状态码以及响应头信息 下面有实例代码
//获取请求地址 req.url username=zhangsan&age=20 console.log(req.url) // 拿到处理过后的参数 pathname不包含参数的请求地址 query请求时携带的数据对象 const { pathname, query} = url.parse(req.url, true) query可以拿去使用因为是数据 pathname可以拿去做判断当前路径是否正确 //这个方法可以设置响应头以及请求状态码信息 res.writeHead(200, { 'Content-Type': 'text/plain;charset=utf-8' }); //res.end 用来返回响应的 if (pathname === '/index' || pathname === '/'){ res.end('欢迎来到首页') } else if (pathname === '/list'){ res.end('欢迎来到列表页') }else{ res.end('页面不存在') }
-
post请求
1 接受post请求参数是通过事件监听绑定事件回调函数的形式获取的
2 开始: 数据开始传输的时候触发req的data事件,并且可以回调函数的params参数中拿到每一项数据 例:req.on('data',params => { }) 整条数据是 username=123&password=789 这样的格式
3 结束: 数据传输结束触发req的end事件
4 后端要使用的话 可以通过系统模块queryString.parse方法把这条数据转换成一个对象,下面有代码//引入queryString模块 const queryString = require('queryString') let postParams = '' //当请求参数开始传输的时候触发data事件 req.on('data', params => { //直接打印params的话是一个Buffer数据,看不懂。<Buffer 75 73 65 72 6e 61 6d 65 3d 31 32 33 26 70 61 73 73 77 6f 72 64 3d 33 34 35> console.log(params) //把每一项数据拼接起来拼接成一个query字符串 username=123&password=678 postParams += params }) //当请求参数传输结束的时候触发end事件 req.on('end', () => { //数据都传输完了把数据通过queryString.parse()方法转换成一个对象 { username: '123', password: '678' } console.log(queryString.parse(postParams)) }) //返回响应 res.end('ok')
-
get请求
-
-
路由
路由是指浏览器和服务器请求的对应关系,简单的说就是根据请求时的地址判断应该返回什么的一个标识就叫路由
-
异步编程
nodejs中异步的操作有很多,比如读取文件fs.readfile,但异步多了就会造成回调地狱。 下列是解决办法
- Promise
promise是es6出的一个解决回调地狱的办法,让我们可以在函数外拿到函数的返回结果。下面是一个例子/** Promise语法: * 语法 Promise构造函数要传一个匿名函数进来,可以接受resolve,reject参数 * 1. resolve: 函数类型 可以看成是调用函数,成功时把要返回的参数传递出去可以 * 在promise实例对象中的.then方法的回调函数中拿到 * * 2. reject: 函数类型 可以看成函数调用, 失败时把要传递的参数传递出去可以 * 在promise实例对象中的.catch方法的回调函数中拿到 * * 3. 连续多个.then()调用: Promise允许链式调用promise,但要求前一个promise对象中返回一个promise对象 * 这样才可以继续.then() */ //把promise对象都包在函数中可以保证他们按顺序执行 function p1() { return new Promise((resolve, reject) => { //异步代码写在Promise构造函数传入的匿名函数中在对应场景下用对应的方法返回出去 fs.readFile('./1.txt', 'utf8', (err, result) => { resolve(result) }) }) } function p2() { return new Promise((resolve, reject) => { //异步代码写在Promise构造函数传入的匿名函数中在对应场景下用对应的方法返回出去 fs.readFile('./2.txt', 'utf8', (err, result) => { resolve(result) }) }) } function p3() { //异步代码写在Promise构造函数传入的匿名函数中在对应场景下用对应的方法返回出去 return new Promise((resolve, reject) => { fs.readFile('./3.txt', 'utf8', (err, result) => { resolve(result) }) }) } //promise.then()中要传一个匿名函数,这个匿名函数可以接收到resolve()中传递的参数 p1().then(res => { console.log(res) // 1 //看上面代码可以看出 p2()中返回了一个promise对象. return p2() }) //可以promise.then().then().then()这样调用,但是前面的.then()中要返回一个 promise对象 .then(res => { console.log(res) //2 //看上面代码可以看出 p3()中返回了一个promise对象. return p3() }) //可以promise.then().then().then()这样调用,但是前面的.then()中要返回一个 promise对象 .then(res => { console.log(res) //3 }) //执行结果 1 2 3
- async
- 在普通函数前面加async 这个函数就变成了异步函数
- 异步函数的默认返回值是一个promise对象,就算你return 手动返回一个值这个值也会被包装一个promise对象。
- 在这个异步函数中返回错误不是用reject()了,而是使用throw关键字: throw 'xx',可以通过.catch()中的函数拿到
- 这样弥补了promise太过臃肿的结构省去了很多代码。
- Promise
- await
- await只能出现在异步函数中
- await要跟一个promise对象
- await可以暂停异步函数的执行,等待promise对象返回结果后再向下执行
- await只能在异步函数中用也就是必须配合async 使用
- await能直接拿到后面那个promise对象中.then函数拿到的参数
大概就是这个意思 let a = await p1 let b = p1.then(res => console.log(res)) a = b
- node中处理异步需要用到util模块中的方法,这个在第三方模块目录中有说明,请往上翻
-
mongodb
- 下载安装: 其他文章中有 https://www.jianshu.com/p/79a848ca19c7
- 把数据导入数据到数据库操作
mongoimport -d 数据库名称 -c 集合名称 --file 要导入的数据文件名称 - 概念
- database 数据库 可以理解为整个数据文件
- collection 集合 一组数据的集合,可以理解为js中的数组
- document 文档 一条具体数据,可以理解为js中的对象
- field 字段 文档中的属性名称,可以理解为js中对象的key
- 使用
- 连接数据库
- 下载mongoose第三方插件,这个插件使node可以操作mongodb
- 引入使用mongoose.connect()方法连接,括号内传数据库的协议://域名:名字,这个方法会返回一个promise对象,用作判断是否连接成功,像下面这样
- 连接数据库时,如果发现没有这个数据库的话会自动创建,所以不用单独创建,直接写就好
const mongoose = require('mongoose') // 协议://地址:数据库名 mongoose.connect('mongodb://localhost:first',{ useUnifiedTopology:true,useNewUrlParser:true}) .then(() => console.log('数据库连接成功')) .catch(err => console.log(err,'数据库连接失败'))
- 连接数据库
- 增删查改
- 增(创建集合 collection 创建文档document)
步骤: 1 先要创建这个集合的规则 2 创建集合 3创建文档(也就是插入数据)- 创建规则: 调用mongoose.schema()方法传入一个对象,对象中有着数据信息,并new返回一个实例对象
- 创建集合: 调用mongoose.model()方法 传入两个值 1集合名称,2集合规则,但不插入数据数据库中就不会创建,所以还要插入数据
- 创建文档: 要用集合的实例去调用save()方法 ,下面有例子代码
- 增(创建集合 collection 创建文档document)
//1 创建集合规则 使用mongoose.Schema()方法传入一个对象写明规则,也就是有哪些字段
const courseSchema = new mongoose.Schema({
//所谓集合规则也就是数据库中都有哪些字段,写在对象中传入
name:String,
author:String,
isPublished:Boolean
})
//2 创建集合
//步骤:1定义集合规则 2创建集合 3向集合中插入文档
/**
* mongoose.model()方法创建集合,传两个值
* 1 集合名称首字母要大写
* 2 集合规则实例,要根据这个去创建集合中的规则都有哪些字段
* 3 mongoose.model()创建文档,第一个参数是文档名字,这个方法返回的是一个构造函数 这个构造函数就代表这个集合,第一个
* */
const Course = new mongoose.model('Course',courseSchema)
//3 向集合中插入文档,要用集合的实例去调用save()方法
const course = new Course({
//向实例对象中传入对象写明数据,这个对象就是数据库中的文档document
name:'node.js课程',
author:'大宝',
isPublished:true
})
//保存进数据库
course.save();
// 第二种插入文档的方式 推荐这个
// 集合实例.create() 两个参数 1 要插入的文档数据 2回调函数,插入完成会调用
Course.create({name:'javascript',author:'二宝',isPublished:false})
.then(result => console.log(result))
.catch(err => console.log(err))
- 查 (实例对象.find())
1. 实例.find()返回一个promise,也就是说可以在.then中拿到查询结果
2. find()方法可以传入一个对象,这个对象就是指定查询条件
3. lt小于的意思,$in包含的意思,比如可以用在查询年龄区间的场景中,或者当做查询条件//在数据库user中查询年龄大于18小于40的结果 User.find({age:{$gt18,$lt40}}).then(res => console.log(res)) // 在数据库user中查询爱好打篮球的结果 User.find({hobbies:['打篮球']}).then(res => console.log(res)) //在find()后链式调用.select('条件1 条件2') 在条件前加上 - 就表示不查询这个字段 User.find().select('name age -_id').then(res => console.log(res)) //对查询到的年龄进行排序 User.find().sort('age').then(res => console.log(res)) 升序 User.find().sort('-age').then(res => console.log(res)) 降序 //跳过skip() limt()只显示多少条 做分页场景下用,前端传值页数和每页显示多少条就可以 User.find().skip(2).limt(10).then(res => console.log(res)) 降序
- 删
//查找删除一条文档 打印返回的是删除的文档
User.findOneAndDelete(obj).then(res => console.log(res)) 传入删除条件
// 删除多条文档,打印返回的是一个对象,里面会有n 和 ok,n代表删除的数量,ok代表操作成功
// 如果条件不传或者是空对象就会删除所有的数据 慎用!!!
User.deletMany(obj).then(res => console.log(res)) 删除多个,如果是个空对象
- 改
语法:
User.updateOne({查询条件},{要修改的值}).then(res => console.log(res))
User.updateMany({查询条件},{要修改的值}).then(res => console.log(res))
例子:
//修改一条
User.updateOne({name:'李四'},{name:'李狗蛋'}).then(res => console.log(res))
//修改多条 如果查询条件是空对象就会修改所有的
User.updateOne({},{age:18}).then(res => console.log(res))
-
数据库插入文档验证(判断是否符合规则再插入)
- 规则有:长度,类型,最小长度,最大长度,最小值,最大值,时间,分类判断,自定义规则
- 具体看下面代码 都有例子
- 下列代码中也有读取错误提示信息的代码示例
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost:test',{useUnifiedTopology:true,useNewUrlParser:true})
.then(() => console.log('数据库连接成功'))
.catch(() => console.log('数据库连接失败'))
//创建集合规则
const personSchema = new mongoose.Schema({
title:{
//minlength maxlength针对字符串类型
type:String, //类型 字符串
required:[true,'请传入title'], //必传,数组中第二个值是自定义的错误提示
minlength:[2,'最小长度是2'], //最小长度为2,数组中第二个值是自定义的错误提示
maxlength:[5,'最5大长度是5'], //最大长度为5,数组中第二个值是自定义的错误提示
trim:true
},
age:{//年龄
//min max最大值最小值 针对数值类型
type:Number, //
min:[18,'不能小于18'], //最小18
max:[60,'不能大于60'] //最大60
},
publisDate:{//时间
type:Date, //时间类型
default:Date.now //设置了默认时间,传入的时候不传也可以
},
category:{//分类
type:String,
//分类 这个会枚举属性值 也就是数组,判断传入的是不是数组中的值,不是的话传入失败
enum:{
values:['html','css','js'], //传入的值的类型
messages:'传入的category值不符合规则' //自定义错误信息
}
},
author:{//自定义判断规则
type:String,
validate:{ //自定义判断规则
validator: v => {
// 1 要返回布尔值
// 2 true验证成功
// 3 false验证失败
// v 要验证的值
return v && v.length > 4
},
//自定义错误信息
message:'传入的值不符合验证规则'
}
}
})
// 创建集合 3个值: 1标识,2规则,3集合名字
const Person = mongoose.model('Person',personSchema,'Person')
//插入文档
Person.create({title:'标题',age:21,category:'js',author:'zyghhhh'})
.then(res => console.log(console.log(res,'插入成功')))
.catch((error) => {
//这里的代码是要获取错误信息 是只打印错误的提示信息
var err = error.errors
//每个错误信息都是一个对象,错误提示是message
//都存在error中 error也是一个对象,所以通过枚举拿到每个对象中的message
for(var attr in err){
console.log(err[attr]['message'])
}
})
-
集合关联:
解释:就好比一个网站中的文章集合和列表集合,文章中会有作者,这个作者就是用户注册网站时的id,这就形成了文章集合和用户结合的关联,文章集合中的作者是用户集合中的用户。网站中有人想要查看文章作者的详情,点进去就会使个人中心页面,这个页面中的数据都要从用户集合中查出来,这就是一个业务场合
步骤:
1. 使用id对集合进行关联
2. 使用populate方法进行关联的集合的查询
// 集合关联模块
const mongoose = require('mongoose')
// 连接数据库
mongoose.connect('mongodb://localhost:test2',{useUnifiedTopology:true,useNewUrlParser:true})
.then(() => console.log('数据库连接成功'))
.catch(() => console.log('数据库连接失败'))
//创建用户集合规则
const UserSchema = new mongoose.Schema({name:String})
//创建文章集合规则
const PostSchema = new mongoose.Schema({title:String,author:{
/**
* mongoose.schema.Types.ObjectId 这串可以拿到每条数据的_id 这是一个特殊的类型
* 做法:
* 1.读取_id
* 2.指定要关联那个表
* 3.使用mongoose.find().populate('数据名') 就可以读取到了,代码就是最后一行
*/
type:mongoose.Schema.Types.ObjectId, //读_id
ref:'User' //指定要关联的集合
}})
//创建用户集合
const User = mongoose.model('User',UserSchema,'User')
//创建文章集合
const Post = mongoose.model('Post',PostSchema,'Post')
User.create({name:'三宝'}).then(res => console.log(res,'数据插入成功'))
Post.create({title:'红楼梦',author:'5e17ec3f9f9e2c2ad89e6cb2'}).then(res => console.log(res,'数据插入成功'))
Post.find().populate('author').then(res => console.log(res))
-
摸版引擎
art-template:第三方模块,作用是数据和摸版拼接在一起
- 下载引入这个模块,这个模块返回的是一个方法,这个方法传2个值
- 值1: 摸版的路径 摸版必须是.art后缀,里面写的html代码,路径要用绝对路径,建议使用path模块的path.join()拼接
- 值2: 数据,对象形式
- 使用:在摸版中{{}}这样就可以读取数据,比如
const template = require('art-template')
const path = require('path')
// template模块暴露的是一个方法可以把摸版和数据进行拼接
// 2个值 1: 摸版路径 2:数据
const html = template(path.join(__dirname,'views','index.art'),{
name:'张三',
age:20
})
console.log(html)
-
中间件
- 中间件可以设置多个,但是后面的想要生效,前面的中间件得调用next()方法,允许进入下一个中间件
-
use中间件
- use中间件可以接受所有的请求,然后根据这个特性可以做出判断
- use中间件的使用场景有很多,比如路由保护,网站维护,自定义404页面
-
express使用
- 创建服务器对象 const app = express()
- 监听端口 app.listen(3000)
- 中间件 app.use() 会拦截所有请求
- get请求 app.get('/add',(req,res) => {})
- get请求拿参数, 可以在req.query中拿到
- post请求app.post('/post',(req,res) => {})
- post请求拿参数, 可以在req.body中拿到
- 拿占位符参数 index/:id 可以在/index路由的req.params中拿到
- 静态资源访问:
//把静态资源目录public放在
// 值1:指定一个虚拟路由路径, 值2:静态资源文件夹目录 绝度路径
app.use('/static',express.static(path.join(__dirname,'public')))
- 错误捕获: 可以使用 try catch配合使用, 代码会先执行try中的代码 如果有错,会给catch传递一个参数,在catch中把调用next()错误传递给错误处理中间件,这样页面不会报错,后台可以捕获到错误
app.get('/index',async (req,res,next) => {
try{
/**
* const promisify = require('util').promisify
const readFile = promisify(fs.readFile)
readFile是这么包装过的,还是用来读取文件的
*
*/
await readFile('./aa.js')
}catch (ex) {
next(ex);
}
})
//错误捕获中间件
app.use((err,req,res,next) => {
res.status(500).send(err.message)
})
网友评论