Express 框架

Express 框架

认识 Web 框架

  • 前面我们已经学习了使用http内置模块来搭建Web服务器,为什么还要使用框架?
    • 原生http在进行很多处理时,会较为复杂;
    • URL判断、Method判断、参数处理、逻辑代码处理等,都需要我们自己来处理和封装;
    • 并且所有的内容都放在一起,会非常的混乱;
  • 目前在Node中比较流行的Web服务器框架是expresskoa
    • 我们先来学习express,后面再学习koa,并且对他们进行对比;
  • express早于koa出现,并且在Node社区中迅速流行起来:
    • 我们可以基于express快速、方便的开发自己的Web服务器;
    • 并且可以通过一些实用工具和中间件来扩展自己功能;
  • Express整个框架的核心就是中间件,理解了中间件其他一切都非常简单!

Express安装

  • express的使用过程有两种方式:

    • 方式一:通过express提供的脚手架,直接创建一个应用的骨架;
    • 方式二:从零搭建自己的express应用结构;
  • 方式一:安装express-generator

    • 安装脚手架

      • npm install -g express-generator

        在这里插入图片描述

    • 创建项目

      • express express-demo

        在这里插入图片描述

    • 安装依赖

      • npm install

        在这里插入图片描述

    • 启动项目

      • node bin/www

        在这里插入图片描述

    • 项目搭建完成,目录结构展示

      在这里插入图片描述

  • 方式二:从零搭建自己的express应用结构;

    • 新建一个文件夹(learn_express

    • npm init –y

    • npm install express -S

      在这里插入图片描述

    • 配置脚本(热部署:nodemon

      {
        "name": "learn_express",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "start ": "nodemon ./src/app.js"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "dependencies": {
          "express": "^4.18.1",
          "nodemon": "^2.0.16"
        }
      }
      
    • 新建文件src,在文件src下面新建文件夹app.js,终端输入指令npm start启动项目。

Express的基本使用

  • 我们来创建第一个express项目:

    • 我们会发现,之后的开发过程中,可以方便的将请求进行分离

    • 无论是不同的URL,还是getpost等请求方式;

    • 这样的方式非常方便我们已经进行维护、扩展;

    • 当然,这只是初体验,接下来我们来探索更多的用法;

      const express = require("express");
      
      const app = express();
      
      app.get("/user", (req, res, next) => {
        res.send("用户列表");
      });
      
      app.post("/user", (req, res, next) => {
        res.send("添加成功");
      });
      
      app.delete("/user", (req, res, next) => {
        res.send("删除成功");
      });
      
      app.patch("/user", (req, res, next) => {
        res.send("修改成功");
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      

      在这里插入图片描述

  • 请求的路径中如果有一些参数,可以这样表达:

    • /users/:userId
    • request对象中药获取可以通过req.params.userId;
  • 返回数据,我们可以方便的使用json

    • res.json(数据)方式;
    • 可以支持其他的方式,可以自行查看文档;
    • https://www.expressjs.com.cn/guide/routing.html

认识中间件

  • Express是一个路由和中间件的Web框架,它本身的功能非常少:
    • Express应用程序本质上是一系列中间件函数的调用;
  • 中间件是什么呢?
    • 中间件的本质是传递给express的一个回调函数;
    • 这个回调函数接受三个参数:
      • 请求对象(request对象);
      • 响应对象(response对象);
      • next函数(在express中定义的用于执行下一个中间件的函数);

认识中间件

  • 中间件中可以执行哪些任务呢?

    • 执行任何代码;
    • 更改请求(request)和响应(response)对象;
    • 结束请求-响应周期(返回数据);
    • 调用栈中的下一个中间件;
  • 如果当前中间件功能没有结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件功能,否则,请求将被挂起。

在这里插入图片描述

应用中间件 – 自己编写

  • 那么,如何将一个中间件应用到我们的应用程序中呢?

    • express主要提供了两种方式:app/router.useapp/router.methods
    • 可以是app,也可以是routerrouter我们后续再学习:
    • methods指的是常用的请求方式,比如:app.getapp.post等;
  • 我们先来学习use的用法,因为methods的方式本质是use的特殊情况;

    • 案例一:最普通的中间件

      const express = require("express");
      
      const app = express();
      
      // 直接发送请求 会打印第一句话
      // 当你在第一个中间件 调用next() 这个时候就会打印第一句话和第二句话
      // 依次类推
      
      // 普通中间件都会执行 next函数会调用下一个中间件
      app.use((req, res, next) => {
        console.log("第一个中间件");
        next();
      });
      
      app.use((req, res, next) => {
        console.log("第二个中间件");
        res.send("hello");
        next();
      });
      
      app.use((req, res, next) => {
        console.log("第三个中间件");
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      

      在这里插入图片描述

    • 案例二:path匹配中间件

      const express = require("express");
      
      const app = express();
      
      // 路径中间件 匹配路径,路径相同就执行(普通中间件也会执行)
      // 按照中间件的顺序去执行
      // 必须调用 next() 函数
      app.use((req, res, next) => {
        console.log("第一个中间件");
        next();
      });
      
      app.use("/user", (req, res, next) => {
        console.log("第二个中间件");
        next();
      });
      
      app.use((req, res, next) => {
        console.log("第三个中间件");
        next();
      });
      
      app.use("login", (req, res, next) => {
        console.log("第四个中间件");
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      
      • 当匹配路径是user

      在这里插入图片描述

      • 当匹配路径是login

        在这里插入图片描述

    • 案例三:pathmethod匹配中间件

      const express = require("express");
      
      const app = express();
      
      // localhost:8000 get
      // 请求方式中间件 会匹配请求方式,遇到next() 会执行下一个中间件
      // 普通中间件都会执行
      app.use((req, res, next) => {
        console.log("第一个中间件");
        next();
      });
      // 这里不写请求路径 会被默认为 "/"
      app.get((req, res, next) => {
        console.log("第二个中间件");
        next();
      });
      
      app.post((req, res, next) => {
        console.log("第三个中间件");
        next();
      });
      
      app.use("/login", (req, res, next) => {
        console.log("第四个中间件");
        res.send("登录成功");
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      
      • 当发送请求的方式为:localhost:8000 get

        在这里插入图片描述

      • 当请求方式为:localhost:8000/login get

        在这里插入图片描述

    • 案例四:注册多个中间件

      const express = require("express");
      
      const app = express();
      
      app.use(
        (req, res, next) => {
          console.log("第一个中间件");
          next();
        },
        (req, res, next) => {
          console.log("第二个中间件");
          next();
        },
        (req, res, next) => {
          console.log("第三个中间件");
          next();
        },
        (req, res, next) => {
          console.log("第四个中间件");
          res.send("ok");
        }
      );
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      
      const express = require("express");
      
      const app = express();
      
      app
        .use((req, res, next) => {
          console.log("第一个中间件");
          next();
        })
        .use((req, res, next) => {
          console.log("第二个中间件");
        });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      

应用中间件 – body解析

  • 并非所有的中间件都需要我们从零去编写:
    • express有内置一些帮助我们完成对request解析的中间件;
    • registry仓库中也有很多可以辅助我们开发的中间件;
  • 在客户端发送post请求时,会将数据放到body中:
    • 客户端可以通过json的方式传递;
    • 也可以通过form表单的方式传递;

客户端发送请求的方式

  • 客户端传递到服务器参数的方法常见的是5种:

    • 方式一:通过get请求中的URLparams

      const express = require("express");
      
      const app = express();
      
      // 将请求参数以url地址的形式传递
      // localhost:8000/user/1/admin
      
      app.get("/user/:id/:name", (req, res, next) => {
        const { id, name } = req.params;
        res.send({ id, name });
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      

      在这里插入图片描述

    • 方式二:通过get请求中的URLquery

      const express = require("express");
      
      const app = express();
      
      // 将参数跟在url地址后
      // localhost:8000/user?username=张三&age=20
      
      app.get("/user", (req, res, next) => {
        const { username, age } = req.query;
        res.send({ username, age });
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      

      在这里插入图片描述

    • 方式三:通过post请求中的body的json格式(中间件中已经使用过);

      • 手动实现

        const express = require("express");
        
        const app = express();
        
        // 解析 JSON 数据
        app.use((req, res, next) => {
          let data = "";
          if (req.headers["content-type"] == "application/json") {
            req.on("data", (chunk) => {
              data += chunk;
            });
            req.on("end", () => {
              req.body = JSON.parse(data.toString());
              next();
            });
          }
        });
        
        // JSON 数据放在请求对象的body中
        app.post("/user", (req, res, next) => {
          const { username, age } = req.body;
          res.send({ username, age });
        });
        
        app.listen(8000, () => {
          console.log("服务器开启成功");
        });
        
      • json()

        const express = require("express");
        const bodyparse = require("body-parse");
        
        const app = express();
        
        // 解析 JSON 数据
        app.use(express.json()); 
        
        // JSON 数据放在请求对象的body中
        app.post("/user", (req, res, next) => {
          const { username, age } = req.body;
          res.send({ username, age });
        });
        
        app.listen(8000, () => {
          console.log("服务器开启成功");
        });
        
      • body-parser

        const express = require("express");
        const bodyParser = require("body-parser");
        
        const app = express();
        
        // 解析 JSON 数据
        app.use(
          bodyParser({
            extended: true,
          })
        );
        
        // JSON 数据放在请求对象的body中
        app.post("/user", (req, res, next) => {
          const { username, age } = req.body;
          res.send({ username, age });
        });
        
        app.listen(8000, () => {
          console.log("服务器开启成功");
        });
        
      • 效果展示

        在这里插入图片描述

    • 方式四:通过post请求中的body的x-www-form-urlencoded格式(中间件使用过);

      const express = require("express");
      
      const app = express();
      
      app.use(
        express.urlencoded({
          extended: true,
        })
      );
      
      app.post("/user", (req, res) => {
        const { username, age } = req.body;
        res.send({ username, age });
      });
      
      app.listen(8000, () => {
        console.log("服务器开启成功");
      });
      

      在这里插入图片描述

    • 方式五:通过post请求中的form-data格式(中间件中使用过);

      • 首先需要通过终端安装一个插件npm i multer

        // 文件上传 还是普通的表单数据都需要安装 multer 插件
        const express = require("express");
        const multer = require("multer");
        
        const app = express();
        
        // 文件上传的中间件
        const upload = multer({
          dest: "uploads/",
        });
        
        // 单文件上传
        // file 为文件的名称
        app.post("/upload", upload.single("file"), (req, res, next) => {
          console.log(req.body);
          res.send(req.file);
        });
        
        app.listen(8000, () => {
          console.log("服务器开启成功");
        });
        
      • 发送请求

        在这里插入图片描述

      • 以上会发现我们的文件上传没有后缀名,无法之间双击打开

      • 所以这个时候需要配置一个随机生成的文件后缀名

        // node 的内置模块
        const path = require("path");
        
        const { nanoid } = require("nanoid");
        
        // 文件上传 还是普通的表单数据都需要安装 multer 插件
        const express = require("express");
        const multer = require("multer");
        
        // 创建服务对象
        const app = express();
        
        const storage = multer.diskStorage({
          // 文件上传的目录
          destination(req, file, callback) {
            callback(null, "uploads/");
          },
          // 自定义上传文件的名称
          filename(req, file, callback) {
            // file.originalname 文件的完整名称
            // 后缀名
            const extname = path.extname(file.originalname);
            callback(null, nanoid() + extname);
          },
        });
        
        // 文件上传的中间件
        const upload = multer({
          storage,
        });
        
        // 单文件上传
        // file 为文件的名称
        app.post("/upload", upload.single("file"), (req, res, next) => {
          // 请求体
          console.log(req.body);
          // 文件上传成功后的文件对象
          res.send(req.file.path);
        });
        
        app.listen(8000, () => {
          console.log("服务器开启成功");
        });
        

Express的路由

  • 如果我们将所有的代码逻辑都写在app中,那么app会变得越来越复杂:

    • 一方面完整的Web服务器包含非常多的处理逻辑;
    • 另一方面有些处理逻辑其实是一个整体,我们应该将它们放在一起:比如对users相关的处理
      • 获取用户列表;
      • 获取某一个用户信息;
      • 创建一个新的用户;
      • 删除一个用户;
      • 更新一个用户;
  • 我们可以使用express.Router来创建一个路由处理程序:、

    • 一个Router实例拥有完整的中间件和路由系统;
    • 因此,它也被称为迷你应用程序(mini-app);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值