express框架

更新时间: 2024-11-05 15:41:13

# express介绍

express是一个基于Node.js平台的极简、灵活的WEB应用开发框架,官方网址:https://www.expressjs.com.cn/ (opens new window)
简单来说,express是一个封装好的工具包,封装了很多功能,便于我们开发WEB应用(HTTP服务)

# express的初体验

// 1.导入express
const express = require('express')

// 2.创建应用对象  
const app = express()  

// 3.创建路由
app.get('/home',(req, res) => {
    res.end('hello express')
})

// 4. 监听端口,启动服务
app.listen(3000, () => {
    console.log('服务已经启动,端口 3000 正在监听中....')  
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 路由的介绍

官方定义:路由确定了应用程序如何响应客户端对特定端点的请求

# 路由的使用

一个路由的组成有请求方法,路径和回调函数组成

express中提供了一系列方法,可以很方便的使用路由,使用格式如下:

app.<method>(path, callback)

代码示例:

// 导入 express
const express = require('express') 

// 创建应用对象 
const app = express()

// 创建get路由
app.get('/home',(req,res) => {
  res.end('网站首页') 
})

// 首页路由
app.get('/', (req, res) => {
  res.end('我才是真正的首页')
})

// 创建post路由
app.post('/login', (req, res) => {
  res.end('login' )
})

// 匹配所有的方法
app.all('/test',(req, res) => {
  res.end('test')
})

// 匹配404  
app.all('*', (req, res) => {
  res.end('404 not Found')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 获取请求报文参数

express框架封装了一些API来方便获取请求报文中的数据,并且兼容原生HTTP模块的获取方式

// 导入 express
const express = require('express')

// 创建应用对象 
const app = express()  

// 获取请求的路由规则  
app.get('/request', (req, res) => {
  // 1. 获取报文的方式与原生 HTTP 获取方式是兼容的  
  console.log(req.method)  
  console.log(req.url)
  console.log(req.httpVersion) 
  console.log(req.headers) 

  // 2. express 独有的获取报文的方式  
  // 获取查询字符串  
  console.log(req.query) // 相对重要
  // 获取指定的请求头
  console.log(req.get('host'))
  // 获取ip
  console.log(req.ip)  

  res.send('请求报文的获取')
})

// 启动服务
app.listen(3000, () => {
  console.log('启动成功....')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 获取路由参数

路由参数指的是URL路径中的参数(数据)

app.get('/:id.html',(req, res) => {
  res.send('商品详情,商品id为' + req.params.id)  
})
1
2
3

# 响应设置

express框架封装了一些API来方便给客户端响应数据,并且兼容原生HTTP模块的获取方式

// 获取请求的路由规则  
app.get("/response",(req, res) => {
  // 1. express 中设置响应的方式兼容 HTTP 模块的方式  
  res.statusCode = 404  
  res.statusMessage = 'xxx'
  res.setHeader('abc', 'xyz')
  res.write('响应体')
  res.end('xxx')

  // 2. express 的响应方法  
  res.status(500) // 设置响应状态码
  res.set('xxx', 'yyy') // 设置响应头  
  res.send('中文响应不乱码') // 设置响应体  

  // 连贯操作
  res.status(404).set('xxx', 'yyy').send('你好朋友')  

  // 3. 其他响应  
  res.redirect('http://atguigu.com') // 重定向
  res.download('./package.json') // 下载响应  
  res.json() // 响应 JSON  
  res.sendFile(__dirname + '/home.html') // 响应文件内容  
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 中间件介绍

中间件(Middleware)本质是一个回调函数
中间件函数可以像路由回调一样的访问请求对象(request),响应对象(response)

中间件的作用就是使用函数封装公共操作,简化代码

# 中间件的类型

  • 全局中间件

  • 路由中间件

  • 定义全局中间件
    每一个请求到达服务端之后,都会执行全局中间件函数

// 声明中间件函数
let recordMiddleware = function(request, response, next) {
  // 实现功能代码
  // .....
  // 执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
  next()
}
// 应用中间件  
app.use(recordMiddleware) 
// 声明时可以直接将匿名函数传递给use  
app.use(function(request, response, next) {
  console.log('定义第一个中间件') 
  next()  
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14

express允许使用app.use()定义多个全局中间件

app.use(function(request, response, next) {
  console.log('定义第一个中间件') 
  next()
})

app.use(function(request, response, next) {
  console.log('定义第二个中间件')
  next()
})
1
2
3
4
5
6
7
8
9
  • 定义路由中间件
    如果只需要对某一些路由进行功能封装,则就需要路由中间件
    调用格式如下:
app.get('/路径', 中间件函数,(request, response) => {

})

app.get('/路径', 中间件函数1,中间件函数2,(request, response) => {

})
1
2
3
4
5
6
7

# 全局中间实践

/**
 * 记录每个请求的url与IP地址  
 */
const express = require('express')
const fs = require('fs')
const path = require('path')

const app = express()

// 声明中间件函数
function recordMiddleware(req, res, next) {
    let {url, ip} = req
    fs.appendFileSync(path.resolve(__dirname, './access.log'), `${url} ${ip}\r\n`)
    next()
}

// 使用中间件函数  
app.use(recordMiddleware)

app.get('/home',(req, res) => {
    res.send('前台首页')
})

app.get('/admin',(req, res) => {
    res.send('后台首页')
})

app.all('*',(req, res) => {
    res.send('<h1>404 Not Found</h1>')
})

app.listen(3000, () => {
    console.log('服务已启动...')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 路由中间件实践

/**
 * 针对 /admin /setting 的请求,要求URL携带code=521参数,如未携带提示【暗号错误】
 */
const express = require('express')
const fs = require('fs')
const path = require('path')

const app = express()

app.get('/home',(req, res) => {
    res.send('前台首页')
})

// 声明中间件
let checkCodeMiddleware = (req, res, next) => {
    if(req.query.code === '521') {
        next()
    }else{
        res.send('暗号错误')
    }
}

app.get('/admin',checkCodeMiddleware,(req, res) => {
    res.send('后台首页')
})

app.get('/setting',checkCodeMiddleware,(req, res)=> {
    res.send('后台设置')
})

app.all('*',(req, res) => {
    res.send('<h1>404 Not Found</h1>')
})

app.listen(3000, () => {
    console.log('服务已启动...')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 静态资源中间件

express内置处理静态资源的中间件

// 引入express框架  
const express = require('express')  
// 创建服务对象
const app = express()
// 静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录 
app.use(express.static('./public')) // 当然这个目录中都是一些静态资源  
// 如果访问的内容经常变化,还是需要设置路由
// 但是,在这里有一个问题,如果public目录下有index.html文件,单独也有index.html的路由
// 则谁书写在前,优先执行谁
app.get('/index.html',(request, response)=> {
  response.send('首页')
})
// 监听端口
app.listen(3000, () => {
  console.log('3000 端口启动')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意

  1. index.html 文件为默认打开的资源
  2. 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
  3. 路径响应动态资源,静态资源中间件响应静态资源

# 获取请求体数据

express可以使用body-parser包处理请求体

  • 第一步:安装
  npm i body-parser
1
  • 第二步:导入body-parser包
const bodyParser = require('body-parser')
1
  • 第三步:获取中间件函数
// 处理queryString格式的请求体
let urlParser = bodyParser.urlencoded({extended: false})
// 处理JSON格式的请求体
let jsonParser = bodyParser.json()
1
2
3
4
  • 第四步:设置路由中间件,然后使用request.body来获取请求体数据
app.post('/login',urlParser,(request, response) => {
  // 获取请求体数据
  console.log(request.body) 
  // 用户名
  console.log(request.body.username)
  // 密码
  console.log(request.body.userpass)
  response.send('获取请求体数据')
})
1
2
3
4
5
6
7
8
9

# 防盗链

/**
 * 按照要求搭建 HTTP 服务 
 * 
 * GET /login 显示表单网页  
 * POST /login 获取表单中的 用户名 和 密码
 */

// 导入express
const express = require('express')

// 创建应用对象
const app = express() 

// 声明中间件
app.use((req, res, next) => {
    // 检测请求头中的 referer 是否为127.0.0.1  
    // 获取 referer
    let referer = req.get('referer') 
    if(referer){
        // 实例化
        let url = new URL(referer)
        // 获取 hostname
        let hostname = url.hostname
        // 判断
        if(hostname !== '127.0.0.1') {
            // 响应 404 
            res.status(404).send('<h1>404 Not Found</h1>')
            return
        }
    }
    next()
})

app.use(express.static(__dirname+'/public'))

// 启动服务 
app.listen(3000, () => {
    console.log('server is running...')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 路由模块化

express中的Router是一个完整的中间件和路由系统,可以看做是一个小型的app对象。

作用是对路由进行模块化,更好的管理路由

// homeRouter.js

// 1. 导入 express
const express = require('express')

// 2. 创建路由器对象
const router = express.Router()  

// 3. 在 router 对象身上添加路由  
router.get('/', (req, res) => {
  res.send('首页')
})

router.get('/cart', (req, res) => {
  res.send('购物车')
})

// 4. 暴露
module.exports = router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 主文件  
const express = require('express')  

const app = express()  

// 5. 引入子路由文件
const homeRouter = require('./router/homeRouter')

// 6. 设置和使用中间件
app.use(homeRouter)  

app.listen(3000, () => {
  console.log('3000 端口启动')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 目标引擎的介绍

模版引擎是分离用户界面和业务数据的一种技术

# ejs初体验

EJS是一个搞笑的JavaScript的模板引擎
官网: https://ejs.co/ (opens new window)
中文站:https://ejs.bootcss.com/ (opens new window)

下载安装EJS

npm i ejs --save
1

代码示例:

// 1. 引入ejs  
const ejs = require('ejs')
// 2. 定义数据 
let person = ['张三','李四','王二麻子']  
// 3. ejs解析模板返回结构  
// <%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构  
let html = ejs.render('<%= person.json(",") %>',{person: person}) 
// 输出结果
console.log(html) 
1
2
3
4
5
6
7
8
9

# EJS常用语法

执行JS代码 <% code %>

输出转义的数据到模板上
<%= code %>

输出非转义的数据到模板上
<%- code %>

# ejs列表渲染

// form.html
<ul>
    <% xiyou.forEach(item => { %>
        <li><%= item %></li>
    <% }) %>
</ul>
1
2
3
4
5
6
const ejs = require('ejs')
const fs = require('fs')

const xiyou = ['唐僧','孙悟空','猪八戒','沙僧']

const html = fs.readFileSync('./form.html').toString()

let result = ejs.render(html,{xiyou:xiyou})

console.log(result)
1
2
3
4
5
6
7
8
9
10

# ejs条件渲染

/**
 * 通过 isLogin 决定最终的输出内容  
 * true 输出 <span>欢迎回来</span>
 * false 输出 <button>登录</button>  <button>注册</button>
 */
const ejs = require('ejs')

// 变量
let isLogin = false

let result = ejs.render(`
    <% if(isLogin) { %>
        <span>欢迎回来</span>
    <% }else{ %>
        <button>登录</button><button>注册</button>
    <% } %>
`,{isLogin:isLogin})

console.log(result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# express中使用ejs

// views/home.ejs  注意后缀需要时ejs
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>哈喽 <%= title %></h2>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
const express = require('express')
const path = require('path')

const app = express()

// 1. 设置模板引擎
app.set('view engine', 'ejs')
// 2. 设置模板文件存放位置 模板文件:具有模板内容的文件
app.set('views', path.resolve(__dirname, './views'))

app.get('/home',(req,res) => {
    // 3. render响应 
    // res.render('模板的文件名','数据')
    // 声明变量
    let title = '1234'
    res.render('home', {title})
    // 4.创建模板文件  
})

app.listen(3000, () =>{
    console.log('服务已经启动,端口3000正在监听中')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# express-generator

npm install -g express-generator

# 处理文件上传

const express = require('express')
const path = require('path')
const fs = require('fs')
// 导入formidable
const formidable = require('formidable')  // 安装2.1.2版本  

const app = express()

// 1. 设置模板引擎
app.set('view engine', 'ejs')
// 2. 设置模板文件存放位置 模板文件:具有模板内容的文件
app.set('views', path.resolve(__dirname, './views'))

// 显示网页的表单
app.get('/portrait',(req,res) => {
    res.render('portrait')
})

// 处理文件上传  
app.post('/portrait',(req, res) => {
    // 创建 from 对象
    const form = formidable({
        multiples: true,
        // 设置上传文件的保存目录
        uploadDir: __dirname + '/images',
        // 保持文件后缀
        keepExtensions: true
    })  

    form.parse(req, (err, fields, files) => {
        if(err) {
            console.log(err)
            return
        }
        console.log(fields) // 一般的字段保存在这里
        console.log(files) // file会保存在这里  
        // 服务器保存该图片的访问URL  
        let url = "/images/" + files.portrait.newFilename
        res.send(url)
    })
})

app.listen(3000, () =>{
    console.log('服务已经启动,端口3000正在监听中')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45