一、express模块介绍

  • 官网:https://www.expressjs.com.cn/
  • 基于 Node.js 平台,快速、开放、极简的 Web 开发框架

二、express模块搭建服务器

npm init -y初始化项目

npm install express下载包

require()导入包

  • 要使用express这个包
  • 要下载,导入,使用
  • 新建一个项目文件夹shop,在根目录运行指令
  • 初始化项目配置文件指令: npm init -y
  • 下载包: npm install express
// 1 导入包
const express = require('express');
// 2 创建express的一个实例
const app = express();

// 4 配置路由
// 表示凡是get请求路径是/的,就会调用第二个参数的回调函数
app.get('/',function(req,res){
    // req:表示请求对象
    // res:表示响应对象
    // 给前端的响应
    res.end('hello world')
})

// 表示凡事get请求路径是/login的,就会调用第二个参数的回调函数
app.get('/login',function(req,res){
    res.end('success')
})

// 3 监听端口
app.listen(8080,function(){
    console.log("服务器监听8080端口成功")
})

// 1-3 步骤完成就开启了一个web服务器
// 4 步骤用于处理指定路由的
    // 后端路由:一个路由对应一个资源

三、基本路由

  • 后端路由:一个路由地址对应一个资源
  • 当前端请求一个后端路由的时候,后端会响应一个对应的资源
  • 即使路由地址相同,但是请求方式不同也是两个不同的路由
  • 由于浏览器测试接口就是在地址栏输入地址,默认是get请求,测试接口不方便
  • 我们一般使用postman这类专门的接口测试工具

1.app.get()匹配get请求

app.get('路由',中间件函数)
  • 要求路由精确匹配
  • 只匹配get请求
  • 如果路由写"*",表示匹配所有路由

2.app.post()匹配post请求

app.post('路由',中间件函数)
  • 要求路由精确匹配
  • 只匹配post请求
  • 如果路由写"*",表示匹配所有路由

3.app.all()精确路由

app.all('路由',中间件函数)
  • 要求路由精确匹配
  • 可以匹配任意请求方式
  • 如果路由写"*",表示匹配所有路由

4.app.use()指定路由打头

app.use('路由',中间件函数)
  • 要求指定路由开始
  • 可以匹配任意请求方式
  • 如果第一个参数路由不写,表示匹配所有路由

四、中间件函数

  • app.get(path,中间件函数1[,中间件函数2,…])
  • app.post(path,中间件函数1[,中间件函数2,…])
  • app.all(path,中间件函数1[,中间件函数2,…])
  • app.use([path,]中间件函数1[,中间件函数2,…])
  • []里面的参数是可选择的
  • 中间件函数有三个参数
  • 第一个参数是:req 请求对象
  • 第二个参数是:res 响应对象
  • 第三个参数是:next 下一个中间件函数
  • next调用就会执行下一个匹配的中间件函数
// 1 导入express
const express = require('express');

// 2 创建express实例
const app = express();

// 4 配置路由
// 如果一个请求可以匹配两个路由
// 按照顺序匹配,匹配了一个以后就不继续匹配了
// 如果希望继续匹配
// 要使用到匹配的中间件函数的第三个参数next
app.all('/api',(req,res,next)=>{
    console.log('all api 执行了');
    // next代表的是下一个中间价函数,调用就会执行下一个匹配的中间价函数
    next()
})
app.get('/api',(req,res,next)=>{
    // 中间件函数1
    console.log('get api 函数1执行了');
    next()
},function(req,res){
    // 中间件函数2
    console.log('get api 函数2执行了')
})


// 执行顺序:
// /api匹配了三个中间件函数,先执行第一个中间件函数
// 如果有next()就继续执行下个中间件函数
// 如果没有next()后面的中间件函数就不执行了



// 3 监听端口
app.listen('8080',()=>{
    console.log('服务器开启成功')
})

五、中间件函数参数

1.req请求对象的相关api

1.1 query解析查询字符串

1.2 params动态路由参数

  • req的相关api
  • req.query: 可以获取get请求的查询字符串,并解析成对象格式
  • req.params: 可以获取动态路由的参数,并解析成对象格式
  • 动态路由
  • 路由中有一部分内容是不确定的可以写成 /:xxx
// 1 导入express
const express = require('express')

// 2 创建express实例
const app = express()

// 4 配置路由
// 请求地址:http://localhost:8080/api
// 请求方式:get
// 查询字符串:req.query
app.get('/api',(req,res)=>{
    console.log("有get请求到了,获取到的查询字符串是")
    console.log(req.query); // 获取查询字符串,并转化成对象
    res.end('有get请求到了,获取查询字符串')
})

// 请求地址:http://localhost:8080/detail/123/lucy
// 请求方式:get
// 动态路由:请求地址中有一部分内容是不确定的,但是有要能获取这个不确定的内容
// 动态路由传入部分: req.params
app.get('/detail/:id/:type',(req,res)=>{
    // :id 是不确定的内容
    // :type 是不确定的内容
    console.log(req.params);// 动态路由传入部分解析成对象:{id:123,type:'lucy'}
    res.end('动态路由')
})

// 请求头里面的cookie的获取要依赖第三方中间件
// post请求的请求主体的获取要依赖第三方中间件

// 3 监听端口
app.listen(8080,function(){
    console.log('服务器开启成功')
})

2.res响应对象的相关api

2.1cookie()设置cookie

2.2end()返回格式响应体

2.3json()返回格式响应体

2.4sendFile()显示文件

2.5 download()下载文件

  • res的相关api
  • 通过响应头给浏览器设置cookie
  • 语法:res.cookie(key,value,{expires:‘过期时间的时间对象默认是会话时效’,path:‘cookie的有效路径默认是/’})
  • 发送响应主体
  • 语法:res.end(‘字符串或者buffer格式的响应体’)
  • 语法:res.json(‘object,array,string,boolean,number等数据类型的响应体’)
  • 语法:res.sendFile(‘把指定的绝对路径的文件显示在浏览器’)
  • 语法: res.download(‘把指定的绝对路径的文件让浏览器下载’)
  • 当前文件所在的文件夹的绝对路径
  • 语法: __dirname
console.log(__dirname)

// 1 导入express
const express = require('express');
const path = require('path')
// 2 创建express实例
const app = express()

// 4 配置路由
app.get('/api',(req,res)=>{
    // 前后端都可以设置cookie
    // 用后端响应头来设置cookie,语法:res.cookie(key, value [, options])
    res.cookie('time','lucy',{
        expires:new Date(Date.now()+3600*1000),  // 不用减8小时,后端会自动处理
        path:'/'
    })

    // 返回响应主体
    // res.end('hello cookie');  // ()里面一般是buffer或者字符串
    // res.json({name:'lucy',age:12});  // ()里面可以是对象,数组,数值,...

    // __dirname : 当前文件所在的文件夹的绝对路径
    // res.download(path.join(__dirname,'package.json'));// ()里面是一个绝对路径,会触发浏览器下载文件
    // res.sendFile(path.join(__dirname,'package.json'))// ()里面是一个绝对路径,会把文件直接显示在浏览器中

})


// 3 监听端口
app.listen(8080)
// req.query : 解析好的查询字符串
console.log(req.query)
// req.params: 解析好的动态路由
console.log(req.params)
// res.cookie:设置cookie
req.cookie('key','value',{
    domain:'qf.com',
    expires:new Date(Date.now() + 900000),
    path:'/abc'  // 默认"/"
})
// res.status: 设置响应状态码
res.status(406)
// res.end(a Buffer object, a String): 设置响应主体
// res.json(object, array, string, Boolean, number, or null): 设置响应主体
// res.sendFile: 设置浏览器显示文件
// 文件路径要是绝对路径
res.sendFile(path.resolve(__dirname,'index.html'))
// res.download: 设置前端下载指定文件
// 文件路径要是绝对路径
res.download(path.resolve(__dirname,'index.html'))
// res.jsonp: 设置响应主体
// res.redirect([status,] path):重定向
// res.send('a Buffer object, a String, an object, Boolean, or an Array'): 设置响应主体

3.next下一个中间件函数

  • next调用就会执行下一个匹配的中间件函数

六、app.use()

1.err错误处理

  • 一般写在所有的路由配置的最末尾
  • 作用:处理前面的中间件中出现的错误,以免服务器瘫痪
  • 语法:app.use((err,req,res,next)=>{})
  • 语法:四个参数缺一不可,缺了一个就不是错误处理中间件
// 1 引入express
const express = require('express');

// 2 创建express实例
const app = express()

// 4 配置路由
// 请求地址: http://localhost:8080/api
// 请求方式: get
app.get('/api',(req,res)=>{
    console.log("http://localhost:8080/api get");
    console.log(a); // 这里有语法错误,a is not defined
    // 返回响应
    res.json({page:'api'})
})

// 5 在配置完所有路由以后,写一个错误处理中间件
// 语法:app.use((err,req,res,next)=>{})
// 要求:必须有四个参数,不能省略任何一个
// 第一个:错误信息
// 第二个:请求对象
// 第三个:响应对象
// 第四个:下一个中间件
app.use((err,req,res,next)=>{
    // 在后端处理输出这个语法错误
    // console.log(err)
    // 给前端响应
    res.json({help:'msg error'})
})

// 3 监听端口
app.listen(8080,()=>{
    console.log('服务器开启成功')
})

2.express.static()静态资源

  • 语法:app.use(express.static(‘静态资源文件夹路径’))
  • 资源中间件尽量放在所有路由配置的最前面
  • 在路由匹配的时候
  • 如果路由是/index.html
  • 就先去静态资源文件夹的路径里面找index.html,找到了,直接返回响应,没找到就继续后面的路由匹配
  • 静态资源中间件可以写多个,按顺序匹配
// 1 导入express
const express = require('express');
const path = require('path')
// 2 实例化express
const app = express();

// 需求
// public文件夹,里面是前端给我的html,js,css,img资源
// 文件夹里面的html文件,css文件,js文件,图片文件很多
// 如果我自己配置路由,每个文件都要配置一个路由
// 不难,但是很麻烦
app.get('/index.html',(req,res)=>{
    res.sendFile(path.join(__dirname,'public','index.html'))
})

// 3 监听端口
app.listen(8080,()=>{
    console.log('服务器开启成功')
})
var express = require('express')
var app = express()

app.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

3.express.urlencoded请求主体解析

express的post请求主体解析的内置中间件:bodyParser

  • 在路由配置的最前面设置
  • app.use(express.urlencoded())
  • 解析 application/x-www-form-urlenocded格式的请求主体
  • app.use(express.json())
  • 解析application/json格式的请求主体
  • 使用这个中间件以后
  • 在后面的所有路由的请求对象中,就有req.body
  • 就是解析好的请求主体
// 1 引入express
const express = require('express');
// 2 实例化express
const app = express();

// 使用bodyParser中间件
app.use(express.json())
app.use(express.urlencoded())

// 4 配置路由
app.post('/api',(req,res)=>{
    console.log(req.body);// 解析好的请求主体
})

// 3 监听端口
app.listen(8080,()=>{
    console.log('服务器开启成功')
})

4.router.use()路由中间件

var express = require('express')
var app = express()
var router = express.Router()

// 没有路由的,是针对router的每一个请求
router.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

// 针对动态路由 /user/:id
router.use('/user/:id', function (req, res, next) {
  console.log('Request URL:', req.originalUrl)
  next()
}, function (req, res, next) {
  console.log('Request Type:', req.method)
  next()
})

// 针对get方式的动态路由/user/:id
router.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next router
  if (req.params.id === '0') next('route')
  // otherwise pass control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// 针对get方式的动态路由/user/:id
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id)
  res.render('special')
})

//在app上挂载router
app.use('/', router)