第九章:express框架

express 框架


Express

一、express 介绍

express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架(Express 官方地址

简单的来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)

二、express 使用

2.1 express 下载

express 本身是一个 npm 包,所以可以通过 npm 安装

npm init
npm i express

2.2 express 初体验

操作步骤如下:

  1. 创建 JS 文件,写入如下代码:

    // 1.导入 express
    const express = require('express')
    
    // 2.创建应用对象
    const app = express()
    
    // 3.创建路由
    app.get('/home', (req, res) => {
        res.end('<h1>hello express</h1>')
    })
    
    // 4.监听端口 启动服务
    app.listen(3000, () => {
        console.log('服务已经启动,端口 3000 正在监听中...')
    })
    
  2. 命令行下执行该脚本

    node <文件名>
    # 或者
    nodemon <文件名>
    
  3. 然后在浏览器中就可以访问 http://127.0.0.1:3000/home🆗

三、express 路由

3.1 什么是路由

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

3.2 路由的使用

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

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

app.<method>(path, callback)

代码示例:

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

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

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

// 首页路由
app.get('/', (req, res) => {
    res.end('<h1>hello express</h1>')
})

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

// 匹配所有的请求方法
app.all('/search', (req, res) => {
    res.end('<h1>search search search</h1>')
})

// 自定义 404 路由
app.all('*', (req, res) => {
    res.end('<h1>404 Not Found</h1>')
})
// 路由是有先后顺序的,先创建的路由会先执行

// 监听端口 启动服务
app.listen(3000, () => {
    console.log('服务已经启动 端口监听为 3000')
})

3.3 获取请求参数

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)
    console.log('---------------------------')

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

    res.end('<h1>hello express</h1>')
})

// 监听端口 启动服务
app.listen(3000, () => {
    console.log('服务已经启动,端口 3000 正在监听中...')
})

3.4 获取路由参数

路由参数指的是 URL 路径中的参数(数据)。语法格式如下:

req.params.占位符
// 注意:占位符是什么,req.params后面跟的就是什么(两者要保持一致)

代码示例:

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

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

// 使用占位符(:id),然后根据占位符去获取 URL 路由参数,再根据参数返回不同的页面
app.get('/:id.html', (req, res) => {
    // 获取 URL 路由参数
    console.log(req.params.id)
    let id = req.params.id
    res.setHeader('content-type', 'text/html;charset=utf-8')
    if(id === 'login') {
        res.end('<h1>首页</h1>')
    }else if(id === 'money') {
        res.end('<h1>商品详情</h1>')
    }else {
        res.end('<h1>注册页面</h1>')
    }
})

// 监听端口 启动服务
app.listen(3000, () => {
    console.log('服务已经启动,端口 3000 正在监听中...')
})

3.5 练习

根据路由参数响应歌手的信息,路径结构如下:

/singer/1.html

显示歌手的姓名和图片,代码示例:

// 导入 express
const express = require('express')
// 导入 json 文件
const {singers} = require('./JSON/singers.json')

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

// 创建路由
app.get('/singer/:id.html', (req, res) => {
    // 获取路由参数
    let {id} = req.params
    // 在数组中寻找对应 id 的数据
    let result = singers.find(item => {
        // 判断
        if(item.id === Number(id)) {
            return true
        }
    })

    // 要判断得到的结果是否为对象,即是否存在该数据
    if(!result) {
        // 没有的数据,就设置响应状态码为 404
        res.statusCode = 404
        res.end('<h1>404 Not Found</h1>')
        return
    }
    
    // 设置响应体,展示最终结果
    res.end(`
        <!DOCTYPE html>
        <html lang="zh-CN">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>歌手展示</title>
        </head>
        <body>
            <h2>${result.singer_name}</h2>
            <img src="${result.singer_pic}" />
        </body>
        </html>
    `)
})

// 监听端口 启动服务
app.listen(9000, () => {
    console.log('服务已经启动 端口 9000 正在监听中...')
})

四、express 响应设置

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

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

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

// 设置路由
app.get('/response', (req, res) => {
    // 1.express 中设置响应的方式兼容 HTTP 模块的方式(原生响应)
    // res.statusCode = 404
    // res.statusMessage = 'love'
    // res.setHeader('xxx', 'yyy')
    // res.write('<h1>hello express</h1>')
    // res.end('<h1>response</h1>')

    // 2.express 独有的设置响应的方法
    // res.status(500)     //设置响应状态码
    // res.set('abc', 'def')   //设置响应头
    // res.send('你好 Express')    //设置响应体(注意:使用 send 方法设置响应体不会出现中文乱码的问题)
    // 连贯操作
    res.status(404).set('aaa', 'bbb').send('express 框架中可以将这些设置响应连起来')
})

// 监听端口 启动服务
app.listen(3000, () => {
    console.log('服务已经启动 端口 3000 正在监听...')
})

其他响应的设置,代码示例如下:

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

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

// 3.创建路由
app.get('/other', (req, res) => {
    // 1.重定向(跳转响应)
    res.redirect('https://www.csdn.net/')
    // 2.下载响应
    res.download(__dirname + '/package.json')
    // 3.JSON 响应
    res.json({
        name: '云墨书生',
        slogon: '摆烂太久会被收回天赋!'
    })
    // 4.文件响应
    res.sendFile(__dirname + '/test.html')
})

// 4.监听端口 启动服务
app.listen(3000, () => {
    console.log('服务已经启动,端口 3000 正在监听中...')
})

五、express 中间件

5.1 什么是中间件

中间件(Middleware)本质上是一个回调函数,所以有些时候也可以称之为 中间件函数

中间件函数 可以像路由回调一样访问 请求对象(request)、响应对象(response)

5.2 中间件的作用

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

5.3 中间件的类型

  • 全局中间件
  • 路由中间件
(1)定义全局中间件

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

定义全局中间件的步骤:

  1. 声明中间件函数:(函数的形式是没有约束的)

    // 声明中间件函数
    function 函数名(req, res, next) {
        // 实现功能代码
        ......
        // 调用 next 函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用 next)
        next()
    }
    
    // 或者也可以写成箭头函数
    let 函数名 = (req, res, next) => {
        //实现功能代码
        ......
        // 调用 next
        next()
    }
    

    中间件

  2. 使用中间件函数:

    app.use(recordMiddleware)
    
  3. 补充:声明中间件函数时可以直接将匿名函数传递给 use(简写方式)

    app.use(function (req, res, next) {
        console.log('我是一个中间件函数')
        next()
    })
    
(2)多个全局中间件

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

app.use(function (req, res, next) {
    console.log('这是第一个中间件函数')
    next()
})
app.use(function (req, res, next) {
    console.log('这是第二个中间件函数')
    next()
})
(3)定义路由中间件

如果 只需要对某一些路由进行功能封装,则就需要 路由中间件

调用格式如下:

app.get('/admin', 中间件函数, (req, res) => {
    res.send('后台页面')
})

app.get('/setting', 中间件函数1, 中间件函数2, ..., (req, res) => {
    res.send('设置页面')
})

代码示例如下:

// 声明中间件函数
let checkCodeMiddleware = (req, res, next) => {
    // 判断 URL 中是否 code 参数等于 521
    if(req.query.code == '521') {
        next()
    }else {
        res.send('暗号错误')
    }
}
let readMiddleware = (req, res, next) => {
    console.log('我是一个路由中间件')
    next()
}

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

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

5.4 静态资源中间件

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

// 设置静态资源中间件的格式:
app.use(express.static('静态资源的路径'))

// 例如:将当前文件夹下的 public 目录作为网站的根目录
app.use(express.static(__dirname + '/public'))

代码示例:

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

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

// 设置静态资源中间件
app.use(express.static(__dirname + '/public'))
// 如果访问的内容经常变化,还是需要设置路由
// 但是,这里有一个问题:如果 public 目录下有 index.html 文件,同时也有 index.html 的路由(也可以是 / 的路由)
// 此时的情况是:谁书写在前,那么就优先执行谁
// index.html 文件是默认打开的资源

app.get('/index.html', (req, res) => {
    res.send('我才是首页~~~')
})

// 监听端口 启动服务
app.listen(9000, () => {
    console.log('服务已经启动 端口 9000 监听中...')
})

注意事项:

  1. index.html 文件为默认打开的资源
  2. 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
  3. 路由响应动态资源,静态资源中间件响应静态资源(一般情况下)
练习

需求:局域网内可以访问尚品汇的网页

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

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

// 设置静态资源中间件
app.use(express.static(__dirname + '/尚品汇'))

// 监听端口 启动服务
app.listen(9000, () => {
    console.log('服务已经启动 端口 9000 监听中...')
})

5.5 获取请求体数据 body-parser

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

  1. 安装:

    npm i body-parser
    
  2. 导入 body-parser 包

    const bodyParser = require('body-parser')
    
  3. 获取中间件函数

    // 解析 JSON 格式的请求体的中间件
    var jsonParser = bodyParser.json()
    // 解析 querystring 格式请求体的中间件
    var urlencodedParser = bodyParser.urlencoded({ extended: false })
    
  4. 设置路由中间件,然后使用 req.body 来获取请求体数据

    app.post('/login', urlencodedParser, (req, res) => {
        // 获取请求体数据
        console.log(req.body)
        // 获取用户名
        console.log(req.body.username)
        // 获取密码
        console.log(req.body.password)
        res.send('获取表单中的数据')
    })
    
  5. 获取到的请求体数据:

    [Object: null prototype] { username: 'admin', password: '123456' }
    

5.6 图片防盗链

图片防盗链原理:http 标准协议中有专门的字段记录 referer

  1. 它可以追溯到请求时从哪个网站链接过来的
  2. 对于资源文件,可以跟踪到包含显示它的网页地址是什么

因此所有的防盗链方法都是基于这个 Referer 字段

// 导入 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(9000, () => {
    console.log('服务已经启动 端口 9000 监听中...')
})

六、Router

6.1 什么是 Router

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

6.2 Router 作用

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

6.3 Router 使用

  1. 创建独立的 JS 文件(homeRouter.js):

    // 1.导入 express
    const express = require('express')
    
    // 2.创建路由对象(相当于一个小型的 app 对象)
    const router = express.Router()
    
    // 3.创建路由规则
    router.get('/home', (req, res) => {
        res.send('前台首页')
    })
    router.get('/search', (req, res) => {
        res.send('内容搜索')
    })
    
    // 4.对外暴露 router
    module.exports = router
    
  2. 在主文件中导入子路由文件并使用:

    // 导入 express
    const express = require('express')
    // 导入 router
    const homeRouter = require('./routes/homeRouter')
    const adminRouter = require('./routes/adminRouter')
    
    // 创建服务对象
    const app = express()
    
    // 设置
    app.use(homeRouter)
    app.use(adminRouter)
    
    app.all('*', (req, res) => {
        res.status(404)
        res.send('<h1>404 Not Found</h1>')
    })
    
    // 监听端口 启动服务
    app.listen(3000, () => {
        console.log('服务已经启动 端口 3000 监听中...')
    })
    

七、EJS 模板引擎

7.1 什么是模板引擎

模板引擎是分离 用户界面和业务逻辑 的一种技术

7.2 什么是 EJS

EJS 是一个高效的 JavaScript 的模板引擎:

7.3 EJS 初体验

  • 下载安装 EJS

    npm i ejs
    
  • 代码实例:

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

7.4 EJS 常用语法

  • 执行 JS 代码

    <% code %>
    

    代码实例:

    /**
     * 需求:
     *   将数组中的元素按照<ul><li>xxx</li>...</ul>的形式输出
     */
    // 导入 ejs
    const ejs = require('ejs')
    const fs = require('fs')
    const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧']
    
    // EJS 实现
    // <% %> 可以用来执行 JS 代码
    let result = ejs.render(`<ul>
    	<% xiyou.forEach(item => { %>
    	<li><%= item %></li>
    	<% }) %>
    </ul>`, {xiyou})
    
    console.log(result)
    
  • 输出转义的数据到模板上

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

    <%- code %>
    

7.5 express 中使用 ejs

  1. 设置模板引擎

    app.set('view engine', 'ejs')
    
  2. 设置模板文件存放位置(模板文件:具有模板语法内容的文件

    app.set('模板文件夹名称', '模板文件夹路径')
    // 例如:
    app.set('views', path.resolve(__dirname, './views'))
    
  3. 通过 render 方法响应

    // 格式:
    res.render('模板文件名', '数据')
    
    app.get('/', (req, res) => {
    	let title = '云陌殇 君子剑'
    	res.render('home', {title})
    })
    
  4. 创建模板文件(后缀名为:ejs

    创建模板文件

代码示例如下:

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

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

// 1.设置模板引擎(ejs 只是 node.js 模板引擎中的一个。比如:pug、twing)
app.set('view engine', 'ejs')
// 2.设置模板文件存放位置   模板文件:具有模板语法内容的文件
app.set('views', path.resolve(__dirname, './views'))

// 创建路由
app.get('/', (req, res) => {
    // 3.通过 render 方法响应
    // 格式:res.render('模板的文件名', '数据')
    // 声明变量
    let title = '云陌殇 君子剑'
    res.render('home', {title})
    // 4.创建模板文件(例如:home.ejs)
})

// 监听端口
app.listen(9000, () => {
    console.log('服务已经启动...')
})

八、express-generator 工具

通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。下载方式:

  • 通过 npx(包含在 Node.js 8.2.0 及更高版本中)命令来运行 Express 应用程序生成器:(后面会学到 npx)

    npx express-generator
    
  • 通过 npm 将 Express 应用程序生成器安装到全局环境中并使用:

    npm install -g express-generator
    

通过 express -h 可以列出所有可用的命令行参数:

express -h
  
  Usage: express [options] [dir]

  Options:

    -h, --help          输出使用方法
        --version       输出版本号
    -e, --ejs           添加对 ejs 模板引擎的支持
        --hbs           添加对 handlebars 模板引擎的支持
        --pug           添加对 pug 模板引擎的支持
    -H, --hogan         添加对 hogan.js 模板引擎的支持
        --no-view       创建不带视图引擎的项目
    -v, --view <engine> 添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎)
    -c, --css <engine>  添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件)
        --git           添加 .gitignore
    -f, --force         强制在非空目录下创建

创建一个 Express 应用的语法:

express -e 文件夹的名称

// 例如:
express -e generator

入口文件是 bin 目录下的 www.js 文件

  • 22
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值