Node.js(黑马)笔记04(完结)--Express框架

1、Express框架是什么

express框架是一个基于node平台的web应用开发框架,他提供了一系列的强大特性,帮助你创建各种web应用。
我们可以使用npm install express命令下载。

2、Express框架特性
  • 提供了方便简洁的路由定义方式
  • 对获取HTTP请求参数进行了简化处理
  • 对模板引擎支持程度高,方便渲染动态HTML页面
  • 提供了中间件机制有效控制HTTP请求
  • 拥有大量第三方中间件对功能进行扩展
//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

app.get('/',(req,res)=>{
  //send方法来响应,不用使用end方法
  //1、send方法会检测响应内容的类型
  //2、send方法会自动设置http状态码
  //3、send方法会帮我们自动设置响应的内容类型及编码
  res.send('hello express')

})

app.get('/list',(req,res)=>{
  console.log(req.query.name)
  res.send({
    name:'zhangsan',
    age:34,
    address:'beijing'
  })
})
res.end(JSON.stringify(obj))
app.listen(3000)
console.log('网站服务器启动成功')

2.1、指定要公开的目录
const express=require('express')

const server=express()
//指定公开资源的目录
server.use('/public',express.static('./public/'))

server.listen(3000)
console.log('the website is started')

以下也是一种方式

const express=require('express')

const app=express()
// app.use('/public',express.static('./public'))

app.use('/public',express.static('./public'))
app.get('/',(req,res)=>{
  res.send('hello node.js')
})

app.listen(3000)
console.log('the server is started at port 3000')

3、中间件

中间件就是一堆方法,可以接收客户端发来的请求、可以对请求做出响应,也可以将请求继续交给下一个中间件继续处理。

在这里插入图片描述

  • 中间件主要由两部分构成,中间件方法以及请求处理函数。
  • 中间件方法由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。
app.get('请求路径', '处理函数')   // 接收并处理get请求
 app.post('请求路径', '处理函数')  // 接收并处理post请求
  • 默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配。
  • 可以调用next方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件。
//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//请求根目录
app.get('/',(req,res)=>{
  //send方法来响应,不用使用end方法
  //1、send方法会检测响应内容的类型
  //2、send方法会自动设置http状态码
  //3、send方法会帮我们自动设置响应的内容类型及编码
  res.send('hello express')

})


app.get('/request',(req,res,next)=>{
  req.name='zhangsan';
  next()
})

app.get('/request',(req,res)=>{
  res.send(req.name)
})

app.listen(3000)
console.log('网站服务器启动成功')

4、app.use中间件

app.use匹配所有的请求方式,可以直接传入请求处理函数,代表接受所有的请求

app.use((req,res,next)=>{
  console.log(req.url)
  next()
})

app.use 第一个参数也可以传入请求地址,代表不论什么请求方式,只要是这个请求地址就接收这个请求。

app.use('/use',(req,res,next)=>{
  console.log(req.url)
  next()
})

完整案例

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//请求根目录
app.get('/',(req,res)=>{
  //send方法来响应,不用使用end方法
  //1、send方法会检测响应内容的类型
  //2、send方法会自动设置http状态码
  //3、send方法会帮我们自动设置响应的内容类型及编码
  res.send('hello express')

})
//只要发生了请求就要走这个中间件
app.use((req,res,next)=>{
  console.log('请求走了中间件')
  next()
})

app.get('/request',(req,res,next)=>{
  req.name='zhangsan';
  next()
})

app.get('/request',(req,res)=>{
  res.send(req.name)
})


app.listen(3000)
console.log('网站服务器启动成功')

5、中间件的应用

可以作为一个校验机制,进行路由保护

  • 路由保护,客户端在访问需要登录的页面时,可以先使用中间件判断用户登录状态,用户如果未登录,则拦截请求,直接响应,禁止用户进入需要登录的页面。
  • 网站维护公告,在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,网站正在维护中。
  • 自定义404页面
    1、路由保护
//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

app.use('/admin',(req,res,next)=>{
  //使用一个变量模拟是否登录
  let islogin=true;
  if (islogin){
    next()
  }else{
    res.send('您还没有登录,请返回登录')
  }


})

app.get('/admin',(req,res)=>{
  res.send('您已经登录了,可以访问当前页面')
})


app.listen(3000)
console.log('网站服务器启动成功')

2、网站维护

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

app.use((req,res,next)=>{
  res.end('网站正在维护,请果断时间再来访问')
})

app.listen(3000)
console.log('网站服务器启动成功')

3、自定义404页面
这个use应该定义在文件最后,因为这样才穷尽了所有路由,才能报404错误

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
app.get('/find',(req,res)=>{
  res.end('u are looking find page')
})
app.use((req,res,next)=>{
  res.status(404)//设置404状态码,可以链式调用
  res.end('404页面没有找到')
})

app.listen(3000)
console.log('网站服务器启动成功')

6、错误处理中间件

在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败,数据库连接失败。
错误处理中间件是一个集中处理错误的地方。

//错误处理中间件
app.use((err,req,res,next)=>{
  res.status(500).send('服务器发生未知错误')//链式调用,500是错误的状态码
})

完整案例

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//普通路由处理中间件
app.get('/index',(req,res)=>{
  //创建一个错误
  throw new Error('程序发生了未知错误')
})
//错误处理中间件
app.use((err,req,res,next)=>{
  res.status(500).send(err.message)//链式调用,500是错误的状态码
})

app.listen(3000)
console.log('网站服务器启动成功')

ps:只能捕获同步错误,不能捕捉异步处理中间件,只能手动触发这个错误处理中间件
当程序出现错误时,调用next()方法,并且将错误信息通过参数的形式传递给next()方法,即可触发错误处理中间件,这有就可以有程序员来处理。

app.get('/',(req,res,next)=>{
  fs.readFile('./filenotexit',(err,data)=>{
    if (err){
      next(err)
    }
  })
})

实际案例

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//引入文件读取模块
const fs=require('fs')
//异步操作错误中间件
app.get('/index',(req,res,next)=>{
  fs.readFile('./filenotexit','utf8',(err,result)=>{
    if (err!=null){
      next(err)
    }else{
      res.send(result)
    }
  })
})
//错误处理中间件
app.use((err,req,res,next)=>{
  res.status(500).send(err.message)//链式调用,500是错误的状态码
})



app.listen(3000)
console.log('网站服务器启动成功')

7、try catch捕获异步函数错误

在node.js中,异步API的错误信息都是通过回调函数获取的,支持Promise对象的异步API发生错误可以通过catch方法捕获。
异步函数执行如果发生错误要如何捕获错误呢?

try catch 可以捕获异步函数以及其他同步代码在执行过程中发生的错误,但是不能其他类型的API发生的错误。

//异步操作错误中间件
app.get('/index',async (req,res)=>{
  try {
    await User.find({name:'张三'})
  }catch (e) {
    next()
  }
})

实际案例

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//引入文件读取模块
const fs=require('fs')
//引入promisify模块
const promisify=require('util').promisify;
//包装自定义方法
const readFile=promisify(fs.readFile)
//异步操作错误中间件
app.get('/index',async (req,res,next)=>{
  try {
    await readFile('./aaa.js')
  }catch (e) {
    next(e)
  }
})
//错误处理中间件
app.use((err,req,res,next)=>{
  res.status(500).send(err.message)//链式调用,500是错误的状态码
})



app.listen(3000)
console.log('网站服务器启动成功')

8、构建模块化路由

分类对路由进行管理,如可以进行二级路由的管理

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//创建路由对象
const home=express.Router()
//将路由和请求路径匹配
app.use('/home',home)
//在home路由下继续创建二级路由
home.get('/index',(req,res)=>{
  //home/index访问路径
  res.send('这里是二级路由展示页面')
})

app.listen(3000)
console.log('网站服务器启动成功')

9、导出模块化路由

模块一home.js

//引入express框架
const express=require('express')

//创建路由对象
const home=express.Router()
//将路由和请求路径匹配
home.get('/index',(req,res)=>{
  //home/index访问路径
  res.send('这里是home二级路由展示页面')
})
//导出路由
module.exports = home

模块二admin.js

//引入express框架
const express=require('express')

//创建路由对象
const admin=express.Router()
//在home路由下继续创建二级路由
admin.get('/index',(req,res)=>{
  //home/index访问路径
  res.send('这里是admin二级路由展示页面')
})
//导出路由
module.exports = admin

入口文件app.js

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

//导入自定义二级路由
const  home = require('./home')
const  admin = require('./admin')

app.use('/home',home)
app.use('/admin',admin)

app.listen(3000)
console.log('网站服务器启动成功')

10、get参数的获取

Express框架中使用req.query即可获取get参数,框架内部会将get参数转换为对象并返回
//接受地址栏中问号后面的参数
// 例如: http://localhost:3000/?name=zhangsan&age=30

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

app.get('/index',(req,res)=>{
  res.send(req.query)
})

app.listen(3000)
console.log('网站服务器启动成功')

11、post参数的获取

接受post参数需要第三方包body-parser

  • 安装npm install body-parser
  • 引入模块

实例文件
提交表单文件post.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<form action="http://localhost:3000/add" method="post">
  <label>姓名:</label>
  <input type="text" name="name">
  <label>年龄:</label>
  <input type="text" name="age">
  <input type="submit" value="提交">

</form>
</body>
</html>

入口文件app.js

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//引入bodyparser模块
const  bodyparser=require('body-parser')
//对bodyparser模块进行设置
//extened:false 方法内部使用querystring模块处理请求参数的格式
//extended:true 方法内部使用第三方模块qs处理请求参数的格式
app.use(bodyparser.urlencoded({extened:false}))//将解析出来的对象存入body中,extend是扩展方法
//接受请求
app.post('/add',(req,res)=>{
  //接受请求参数
  res.send(req.body)//通过body属性获得post传来的参数对象
})

app.listen(3000)
console.log('网站服务器启动成功')

12、use方法再探

在use方法里面传递了一个参数,可是我也还是没有太理解这样做有什么意义,当然,拦截路由后,可以自定义函数,并根据传入的参数做相应的响应。

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()
//引入bodyparser模块
const  bodyparser=require('body-parser')

app.use(fn({a:1}))//拦截所有路由并调用自定义函数
function fn(obj){
  return function(req,res,next){
    if (obj.a==2){
      console.log(req.url)
    }else{
      console.log(req.method)
    }

    next()
  }
}

app.get('/',(req,res)=>{
  res.send('ok')
})

app.listen(3000)
console.log('网站服务器启动成功')

13、Express路由参数

实际就是把参数写在路由里
使用一个占位符:id进行参数指定

app.get(‘/find/:id’,(req,res)=>{
console.log(req.param)//{id:123}
})
localhost:3000/find/123,其中123就是参数,123与:id是对应关系

案例

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

app.get('/find/:id',(req,res)=>{
  console.log(req.params)
  res.send('had print')
})

app.listen(3000)
console.log('网站服务器启动成功')

输入地址:http://localhost:3000/find/zhangsan
结果,服务器端打印{id:‘zhangsan’}

如果想传递多个参数可以继续在地址后面加/:属性如:’/find/:id/:name/:age’

//引入express框架
const express=require('express')
//直接通过express创建网站服务器
const app=express()

app.get('/find/:name/:age/:address',(req,res)=>{
  console.log(req.params)
  res.send('had print')
})

app.listen(3000)
console.log('网站服务器启动成功')

输入地址:http://localhost:3000/find/zhangsan/25/beijing
结果,服务器端打印{name:‘zhangsan’,age:25,address:beijing}

14、静态资源的处理

通过Express内置的express.static可以方便地托管静态文件,例如img、CSS、JavaScript 文件等。

app.use(express.static('public'))

现在,public 目录下面的文件就可以访问了。

http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

实际案例

//引入express框架
const express=require('express')
//引入path模块
const path=require('path')
//直接通过express创建网站服务器
const app=express()
//实现静态资源访问功能
app.use(express.static(path.join(__dirname,'public')))
app.listen(3000)
console.log('网站服务器启动成功')

地址栏里输入:http://localhost:3000/hello.html
可以直接访问/public下的hello.html文件

15、express-art-template模板引擎
  • 为了使art-template模板引擎能够更好的和Express框架配合,模板引擎官方在原art-template模板引擎的基础上封装了express-art-template
  • 使用npm install art-template express-art-template命令进行安装。(多个模块直接用空格隔开就可以了)

两个模板引擎文件index.art和list.art
index.art

{{msg}}

list.art

{{msg}}

主入口文件app.js

//引入express框架
const express=require('express')
//引入path模块
const path=require('path')
//直接通过express创建网站服务器
const app=express()
//1、告诉express框架使用什么模板引擎渲染什么后缀的模板文件
//1.1模板后缀(art)
//1.2使用模板引擎
//当渲染后缀为art的模板时,使用express-art-template
app.engine('art',require('express-art-template'))
//2设置模板存放目录,告诉express框架模板存放的位置是什么
app.set('views',path.join(__dirname,'views'))//views是模板的存放文件夹,第一个views是固定(且默认)的,第二个views是自定义的
//3、告诉express框架模板的默认后缀是什么
//渲染模板时不写后缀,默认拼接art后缀
app.set('view engine','art')
//index路由
app.get('/index',(req,res)=>{
  //渲染模板
  //1、拼接了模板路径
  //2、拼接了模板后缀
  //3、哪一个模板和哪一个数据进行了拼接
  //4、将拼接结果响应给客户端
  res.render('index',{
    msg:'渲染模板的信息'
  })
})
//list路由
app.get('/list',(req,res)=>{
  res.render('list',{
    msg:'list message'
  })
})

app.listen(3000)
console.log('网站服务器启动成功')

16、app.loacls对象

将变量设置到app.locals对象下面,这个数据在所有的模板中都可以获取到
范例:

app.locals.users=[
  {
    name:'zhangsan',
    age:23
  },
  {
    name: 'lisi',
    age:32
  }
]

两个模板引擎文件index.art和list.art
index.art

{{msg}}
<ul>
  {{each users}}
  <li>
    {{$value.name}}
    {{$value.age}}
  </li>
  {{/each}}
</ul>

list.art

{{msg}}
<ul>
  {{each users}}
  <li>
    {{$value.name}}
    {{$value.age}}
  </li>
  {{/each}}
</ul>

主入口文件app.js

//引入express框架
const express=require('express')
//引入path模块
const path=require('path')
//直接通过express创建网站服务器
const app=express()
//1、告诉express框架使用什么模板引擎渲染什么后缀的模板文件
//1.1模板后缀(art)
//1.2使用模板引擎
//当渲染后缀为art的模板时,使用express-art-template
app.engine('art',require('express-art-template'))
//2设置模板存放目录,告诉express框架模板存放的位置是什么
app.set('views',path.join(__dirname,'views'))//views是模板的存放文件夹,第一个views是固定的,第二个views是自定义的
//3、告诉express框架模板的默认后缀是什么
//渲染模板时不写后缀,默认拼接art后缀
app.set('view engine','art')

//创建一个locals对象
app.locals.users=[
  {
    name:'zhangsan',
    age:23
  },
  {
    name: 'lisi',
    age:32
  }
]

//index路由
app.get('/index',(req,res)=>{
  //渲染模板
  //1、拼接了模板路径
  //2、拼接了模板后缀
  //3、哪一个模板和哪一个数据进行了拼接
  //4、将拼接结果响应给客户端
  res.render('index',{
    msg:'渲染模板的信息'
  })
})
//list路由
app.get('/list',(req,res)=>{
  res.render('list',{
    msg:'list message'
  })
})

app.listen(3000)
console.log('网站服务器启动成功')

结果:
http://localhost:3000/list和http://localhost:3000/index两个路由都可以拿到app.js里面的对象数组

17、使用单独的路由页面

路由页面
router.js

//导入两个主要模块
let app=require('./expressapp')
let fs=require('fs')

module.exports=function(app){//把路由作为一个模块(包含参数的一个函数)导出方便在入口页面把app传入
  app.get('/',(req,res)=>{
    let students=fs.readFile('db.json','utf8',(err,data)=>{
      if (err){
        console.log(err)
      }
      let students=JSON.parse(data).students
      res.render('index.html',{

        fruits:[
          '苹果',
          '香蕉',
          '桔子'
        ],
        students: students
      })

    });


  })
}

主入口文件
expressapp.js

const express=require('express')
const fs=require('fs')
const router=require('./router')

const app=express()
app.use('/public',express.static('./public'))
app.use('/node_modules',express.static('./node_modules'))
//1、配置模板引擎
app.engine('html',require('express-art-template'))
//在入口页面直接使用导入的路由模块,把app作为实参传入
router(app)

app.listen(3000)
console.log('the server is started at port 3000')
module.exports=app

18、使用express和router的标准方式封装路由代码

路由文件
router.js

//导入两个主要模块
let app=require('./expressapp')
let fs=require('fs')

//另外一种思路包装路由
let express=require('express')
//创建一个路由容器
let router=express.Router()
//把路由都挂载到路由容器中
router.get('/',(req,res)=>{
  let students=fs.readFile('db.json','utf8',(err,data)=>{
    if (err){
      console.log(err)
    }
    let students=JSON.parse(data).students
    res.render('index.html',{

      fruits:[
        '苹果',
        '香蕉',
        '桔子'
      ],
      students: students
    })

  });

})

//把router路由容器导出
module.exports=router

入口文件
expressapp.js

const express=require('express')
const fs=require('fs')
const router=require('./router')

const app=express()
app.use('/public',express.static('./public'))
app.use('/node_modules',express.static('./node_modules'))
//1、配置模板引擎
app.engine('html',require('express-art-template'))

//把路由容器挂载到路由容器上
app.use(router)


app.listen(3000)
console.log('the server is started at port 3000')
module.exports=app

19、callback函数获取异步处理结果

当代码中含有异步数据的时候,可以通过callback的形式获取这个异步数据
代码定义:

function add(x,y,callback){
	console.log('======')
	setTimeout(function(){
		var ret=x+y
		 callback(ret)
	}1000}
//这里function的参数的结果就是异步调用的结果
add(4,6,function(ret)){
	//return ret
	console.log(ret)
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值