express框架(学习笔记)

1. 介绍

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

2. express基本使用

2.1 安装依赖包

npm init -y
npm i express

2.2 初体验

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

// 2.创建服务对象
const app = express()

// 3.创建路由
app.get('/home',(req,res)=>{
  res.send('首页~')
})

// 4.监听端口,启动服务
app.listen(3000,()=>{
  console.log('server running~');
})

3. express路由

3.1 什么是路由?

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

3.2 路由的使用

  • 一个路由的组成有 请求方法 路径 回调函数 组成,express 中提供了一系列方法,可以很方便的使用路由,使用格式如下: app . < method > ( path callback )
    // 1.引入express
    const express = require('express')
    
    // 2.创建服务对象
    const app = express()
    
    // 3.创建路由
    app.get('/home',(req,res)=>{
      res.send('首页~')
    })
    
    app.get('/',(req,res)=>{
      res.send('我才是真正的首页~')
    })
    
    app.post('/login',(req,res)=>{
      res.send('登录成功~')
    })
    
    app.all('*',(req,res)=>{
      res.send('<h1>Not Found<h1/>')
    })
    
    // 4.监听端口,启动服务
    app.listen(3000,()=>{
      console.log('server running~');
    })

4. 获取请求报文参数

4.1 获取请求行以及请求头参数

  • 1-3是原生http获取请求报文的属性,后面是express获取请求报文的属性以及方法
  1. 获取请求方法:req.method
  2. 获取请求url:req.url
  3. 获取请求协议版本号:req.httpVersion
  4. 获取ip:req.ip
  5. 获取请求路径:req.url
  6. 获取请求头:req.headers
  7. 获取查询字符串对象:req.query
  8. 获取请求头里边的内容:req.get('请求头的key') 通过get方法获取
  • 完整代码如下:
    // 1.引入express
    const express = require('express')
    
    // 2.创建服务对象
    const app = express()
    
    // 3.创建路由
    app.get('/request',(req,res)=>{
      // 原生http的请求也支持
      // 获取请求方法
      console.log(req.method) // GET
      // 获取请求url路径 
      console.log(req.url) // /request
      // 获取协议版本号
      console.log(req.httpVersion) // 1.1
      // 获取请求头
      console.log(req.headers) 
      //  {
      //     host: '127.0.0.1:3000',
      //     connection: 'keep-alive',
      //     'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"',
      //     'sec-ch-ua-mobile': '?0',
      //     'sec-ch-ua-platform': '"Windows"',
      //     'upgrade-insecure-requests': '1',
      //     'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
      //     accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
      //     'sec-fetch-site': 'none',
      //     'sec-fetch-mode': 'navigate',
      //     'sec-fetch-user': '?1',
      //     'sec-fetch-dest': 'document',
      //     'accept-encoding': 'gzip, deflate, br',
      //     'accept-language': 'zh-CN,zh;q=0.9'
      //   }
    
      // express内部封装的获取请求报文参数的方法
      // 获取ip
      console.log(req.ip) // 127.0.0.1
      // 获取路径
      console.log(req.path) // /request
      // 获取查询字符串
      console.log(req.query) // 访问http://127.0.0.1:3000/request?a=1&b=2   { a: '1', b: '2' }
      // 获取请求头 get方法
      console.log(req.get('host')) //127.0.0.1:3000
      res.send('Hello Express')
    })
    
    // 4.监听端口,启动服务
    app.listen(3000,()=>{
      console.log('server running...')
    })

4.2 获取路由参数

获取路由参数对象:req.params

  • 完整代码如下:
    // 1.引入express
    const express = require('express')
    
    // 2.创建服务对象
    const app = express()
    
    // 3.创建路由
    app.get('/goods/details/:id',(req,res)=>{
      // req.params 来获取路由参数对象 .id和占位符:id对象 参数可随意命名 
      const id = req.params.id
      res.send(`当前页是id为${id}的详情页`)
    })
    
    // 4.监听端口,启动服务 
    app.listen(3000,()=>{
      console.log('server running...');
    })

4.3 路由参数练习

  • 完整代码如下:
    // 1.引入express
    const express = require('express')
    
    // 2.创建服务对象
    const app = express()
    
    /**
     *  导入json数据 可以使用fs读取 但没必要
     *  require引入的json是一个对象可以直接使用
     */
    
    const { singers } = require('./5-singer')
    // 3.创建路由
    app.get('/singers/detail/:id', (req, res) => {
        const result = singers.find(item => {
            return item.id === Number(req.params.id)
        })
        if (result) {
            res.send(`
                <!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>
                    <h1>${result.name}</h1>
                    <img src='${result.pic}'>
                </body>
                
                </html>
            `)
        } else {
            res.send('<h1>Not Found</h1>')
        }
        res.send('嗨嗨')
    })
    
    // 4.监听端口,启动服务
    app.listen(3000, () => {
        console.log('server running...');
    })

4.4 获取请求体

4.4.1 安装第三方包 body-parser , 它是一个中间件

npm i body-parser

4.4.2 引入

// 引入body-paser中间件
const  bodyParser = require('body-parser')

// 获取json格式的请求体
const jsonParser = bodyParser.json()

// 获取querystring格式的请求体
const urlencodedParser = bodyParser.urlencoded({ extended: false })

4.4.3 引用

app.post('/login',urlencodedParser,(req,res)=>{
    // 使用第三方包body-parser这个中间件来获取请求体
    // 这个中间件会想请求体req身上追加一个body属性,这个body存的就是请求体
    res.send(req.body)
})

4.4.4 完整代码

/* 
    实现: 
        get  /login 响应表单页面
        post /login 获取请求体
*/

// 引入express
const express = require('express')
const path = require('path')
// 1.安装body-parser中间件 npm i body-parser

// 引入body-paser中间件
const  bodyParser = require('body-parser')

// 获取json格式的请求体
const jsonParser = bodyParser.json()

// 获取querystring格式的请求体
const urlencodedParser = bodyParser.urlencoded({ extended: false })

// 创建服务对象
const app = express()

// 创建路由规则
app.get('/login',(req,res)=>{
    
    res.sendFile(path.resolve(__dirname+'/10-login.html'))
})

app.post('/login',urlencodedParser,(req,res)=>{
    // 使用第三方包body-parser这个中间件来获取请求体
    // 这个中间件会想请求体req身上追加一个body属性,这个body存的就是请求体
    res.send(req.body)
})

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

5. 响应设置

  • 1-4是原生http的响应设置,后面是express的响应设置
  1. 置响应状态码:res.statusCode = 200
  2. 设置响应状态码描述:res.statusMessage = 'OK'
  3. 设置响应头:res.setHeaser(key,value)
  4. 设置响应体:res.write(字符串/buffer) 可以有多个,res.end(字符串/buffer) 有且只有一个
  5. 设置响应状态码:res.status(200)
  6. 设置响应头:res.set(key,value)
  7. 设置响应体:res.send(字符串/buffer)
  • 完整代码如下:
    // 1.引入express
    const express = require('express')
    
    // 2.创建服务对象
    const app = express()
    
    // 3.创建路由
    app.get('/home', (req, res) => {
        // 原始http响应设置
        // 设置响应状态码
        // res.statusCode = 201
    
        // 设置响应状态码描述
        // res.statusMessage = 'No Data'
    
        // 设置响应头
        // res.setHeader('aaa', 'bbb')
        // res.setHeader('content-type', 'text/html;charset=utf-8')
    
        // 设置响应体
        // res.write('嗨嗨嗨,')
        // res.write('来了啊')
        // res.end('老八')
    
        // express封装的响应设置
        // 设置响应状态
    
        // res.status(201)
        // 设置响应头
    
        // res.set('ccc', 'ddd')
        // 设置响应体
    
        // res.send('我是express设置响应体的方法,我不用设置content-type响应头都不会乱码')
    
        // 重定向响应
        // res.redirect('http://www.baidu.com')
    
        // 下载响应 接收一个绝对路径作为参数
        // res.download(__dirname + '/package.json')
    
        // json响应
        // res.json({
        //     "name": "张三",
        //     "age": 18
        // })
    
        // 响应一个文件 接受一个绝对路径作为参数
        // res.sendFile(__dirname + '/2-路由.js')
    
    
    })
    
    // 4.监听端口,启动服务
    app.listen(3000, () => {
        console.log('服务已启动...');
    })

6. 中间件

6.1 介绍

  • 什么是中间件? 
  • 中间件本质上就是一个回调函数,中间件函数 可以像路由回调一样访问 请求对象(request响应对象(response

6.2 中间件的类型

  • 全局中间件
  • 路由中间件

6.2.1 全局中间件

  • 每一个请求 到达服务端之后 都会执行全局中间件函数
  • 声明全局中间件函数:
    // 定义一个全局中间件 用于记录访客
    function recordMiddleWare(req, res, next) {
        // 实现功能代码
        const { url, ip } = req
        const data = `
            ${ip}在${dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')}访问了 ${url}\r\n
        `
        fs.appendFileSync(__dirname + '/access.log', data)
        next() // 执行next函数(如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
    }
  • 应用中间件
    app.use(recordMiddleWare)
  • 声明时可以直接将匿名函数传递给 use,可以定义多个全局中间件
    app.use((req, res, next)=>{
        console.log('定义第一个测试中间件');
        next();
    })
    app.use((req, res, next)=>{
        console.log('定义第二个测试中间件');
        next();
    })
  • 记录访客代码例子:
    // 记录每个请求的url 和 IP地址 以及访问时间
    
    // 1.引入express
    const express = require('express')
    const fs = require('fs')
    const dayjs = require('dayjs')
    
    // 2.创建服务对象
    const app = express()
    // 定义一个全局中间件 用于记录访客
    function recordMiddleWare(req, res, next) {
        // 实现功能代码
        const { url, ip } = req
        const data = `
            ${ip}在${dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')}访问了 ${url}\r\n
        `
        fs.appendFileSync(__dirname + '/access.log', data)
        next() // 执行next函数(如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
    }
    // 应用中间件
    app.use(recordMiddleWare)
    
    // 3.创建路由
    app.get('/home', (req, res) => {
        res.send('首页')
    })
    
    app.get('/admin', (req, res) => {
        res.send('管理页')
    })
    
    // 4.监听端口,启动服务
    app.listen(3000, () => {
        console.log('server running...');
    })
  • 6.2.2 路由中间件

  • 每一个使用路由中间件的请求都会先执行路有2中间件:
  • 生命路由中间件函数:
    // 创建路由中间件
    function routerWare(req,res,next){
        req.query.code === '521' ? next() : res.send('暗号错误')
    }
  • 应用路由中间件:
  • 完整代码:
    /* 
        针对 /admin /setting的请求 要求URL携带code=521参数
        如果未携带提示暗号错误
    */
    // 1.引入express
    const express = require('express')
    
    // 2.创建服务对象
    const app = express()
    
    // 创建路由中间件
    function routerWare(req,res,next){
        req.query.code === '521' ? next() : res.send('暗号错误')
    }
    
    // 3.创建路由规则
    app.get('/admin',routerWare,(req,res)=>{
        res.send('管理页面')
    })
    
    app.get('/setting',routerWare,(req,res)=>{
        res.send('配置页面')
    })
    
    // 4.监听端口,启动服务
    app.listen(3000,()=>{
        console.log('server running...');
    })
    
    
  • 6.2.3静态资源中间件express.staic()内置中间件

  • 完整代码:
    // 1.引入epxress
    const express = require('express')
    const path = require('path')
    // 2.创建服务对象
    const app = express()
    /**
     *  静态资源中间件
     *      - express.static()
     *      - 参数: 静态资源目录的绝对路径
     *  
     *  静态资源目录即是网站的根目录,客户端访问服务器,
     *  服务器去哪个文件夹去找资源,这个文件夹就是静态资源目录
     * 
     *  注意:访问网站127.0.0.1:3000 路径默认为'/' 
     *       服务端会去静态资源根目录下去找index.html将其返回
     *       如果路由规则中也有'/' 谁先匹配到谁生效,也就是谁在上面谁生效 
     * */
    const staticMiddleWare = express.static(path.resolve(__dirname+'/public'))
    app.use(staticMiddleWare)
    
    // 3.创建路由规则
    app.get('/home',(req,res)=>{
        res.send('首页')
    })
    
    // 4.监听端口,启动服务
    app.listen(3000,()=>{
        console.log('server running');
    })
  • 注意事项:
  1. index.html文件为默认打开的资源  http://127.0.0.1:3000/index.html等同于http://127.0.0.1:3000
  2. 如果静态资源与路由规则同时匹配,则谁先匹配到就响应谁
  3. 一般来说,路由响应动态资源,静态资源中间件响应静态资源

7.路由模块化

  1. 新建routers文件夹 , 文件夹里面新建路由模块的js文件
  2. 在文件中编写以下代码:
    // adminRouter.js
    
    // 1.引入express
    const express = require('express')
    
    // 2.创建路由实例
    const router = express.Router()
    
    // 3.创建路由规则
    router.get('/admin',(req,res)=>{
      res.send('管理页面')
    })
    
    router.get('/log',(req,res)=>{
      res.send('日志页面')
    })
    
    //4.导出路由实例
    module.exports = router
    // homeRouter.js
    
    // 1.引入express
    const express = require('express')
    
    // 2.创建路由实例
    const router = express.Router() // 注意方法Router是大写
    
    // 3.创建路由规则
    router.get('/home',(req,res)=>{
      res.send('前台首页')
    })
    
    router.get('/login',(req,res)=>{
      res.send('登录页面')
    })
    
    // 4.导出路由实例
    module.exports = router
  3. 在server.js文件中 引入路由模块

    // server.js
    
    // 引入express
    const express = require('express')
    // 引入路由模块
    const homeRouter = require('./routers/homeRouter')
    const adminRouter = require('./routers/adminRouter')
    // 创建应用实例
    const app = express()
    
    app.use(homeRouter)
    app.use(adminRouter)
    
    // 监听端口,启动服务
    app.listen(3000,()=>{
      console.log('server running...');  
    })

8.模板引擎ejs

  • 1. 什么是模板引擎?
    模板引擎是用于用户界面 业务数据分离的一种技术,但随着前后端分离,这种技术就少了
  • 2. 安装ejs
    npm i ejs
  • 3. ejs初体验 <%= %>语法
ejs.html


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ejs</title>
</head>

<body>
    <!-- <%= %> ejs的模板语法 类似于模板字符串${}  -->
    <h1>
        <%= weather %>
    </h1>
</body>

</html>
// 1.引入ejs
const ejs = require('ejs')

// 2.定义数据
let weather = '今天天气真不错!'

// 3.引入页面
const fs = require('fs')
const html = fs.readFileSync('./12-ejs.html').toString()

// 4.渲染界面
const result = ejs.render(html,{weather:weather})
console.log(result);
  • 4. ejs列表渲染  <%= %> 包裹的是变量相当于${} , <% %>包裹的js语法,相当于 ``
// ejs列表渲染.js

<!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>
    <ul>
        <% xiyou.forEach(item=>{ %> 
            <li><%= item %></li>
        <% }) %>
    </ul>
</body>

</html>
// ejs.js

const fs = require('fs')
const html = fs.readFileSync('./13.ejs列表渲染.html').toString()
let res = ejs.render(html,{xiyou:xiyou})
console.log(res);
  • 5.ejs条件渲染
// ejs.html 

<!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>
    <header>
        <% if(isLogin){ %>
            <span>欢迎回来</span>
        <% }else{ %>
            <button>登录</button> <button>注册</button>
        <% } %>
    </header>
</body>

</html>
// ejs.js

const ejs = require('ejs')
const fs = require('fs')
let html = fs.readFileSync('./14.ejs条件渲染.html').toString()
let result = ejs.render(html,{isLogin:isLogin})
console.log(result);

6. ejs在express中的应用

创建views文件夹 , 在views文件夹下创建ejs在express中的应用.ejs文件  切记是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>
    <h1>
        <%= title %>
    </h1>
</body>

</html>
// 导入express
const express = require('express')

// 引入path 
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 = '测试ejs在express中的应用'

// 第一个参数要和模板文件的名字保持一致
res.render('ejs在express中的应用',{title:title})

})

// 监听端口,启动服务
app.listen(3000,()=>{
    console.log('server running...');
})

9. express生成器generator (脚手架)

  1. 全局安装
    npm i express-generator -g
  2. 安装之后,全局多了一个命令 express, 通过express -h 查看可用命令

  3. 使用express -e 项目名 来初始化项目

  4. 初始化好项目之后,安装依赖: npm i

  5. 看package.json文件中的脚本 启动服务

  6. 端口默认是3000

 10.文件上传

1.views文件夹下编写前端模板,上传文件form表单页面

// views文件夹下的 upoload.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>
    <h1>文件上传</h1>
    <form action="/handleUpload" method="post" enctype="multipart/form-data">
        <input type="text" name="文件类型"> <br><br>
        <input type="file" name="上传文件"> <br><br>
        <button>提交</button>
    </form>
</body>

</html>

2.文件上传.js

// 文件上传.js

// 1.引入express
const express = require('express')
const path = require('path')
const formidable =  require('formidable')
// 2.创建实例
const app = express()

app.set('view engine','ejs') //设置模板引擎

app.set('views',path.resolve(__dirname,'./views')) // 设置模板引擎查找目录

app.use(express.static(__dirname+'/public'))
// 3.创建路由规则
app.get('/home',(req,res)=>{
    res.render('upload') // 响应模板引擎文件 upload.ejs
})

app.post('/handleUpload',(req,res)=>{
    // res.send('ok ')
    const form = formidable({
        multiples:true,
        keepExtensions:true,
        uploadDir:__dirname+'/public/images'
    });

    form.parse(req, (err, fields, files) => {
        if (err) {
        next(err);
        return;
        }
        // res.json({ fields, files });
        res.send('/images/'+files['上传文件'].newFilename)
    });
})

// 4.监听端口,启动服务
app.listen(3000,()=>{
    console.log('server running...');
})

3. 上边处理文件上传的响应需要使用formidable 插件,详见npm.js  formidable

安装formidable

npm i formidable@v2 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值