Express学习

02模块化路由

  • 模块路由

    const express = require("express");
    
    const app = express();
    
    //1 导入路由模块
    const router = require("./03router");
    
    //2 注册路由模块
    //也可以添加前缀    http://localhost/api/user/list才能访问
    app.use("/api", router);
    
    //app.use();作用    用来注册全局中间件
    app.listen(80, () => {
      console.log("service start");
    });
    
    
  • 入口文件

    //路由模块
    
    //1 导入express
    const express = require("express");
    
    //2 创建路由对象
    const router = express.Router();
    
    //3 挂载具体路由
    router.get("/user/list", (req, res) => {
      res.send("get user list");
    });
    
    router.post("/user/add", (req, res) => {
      res.send("post user add");
    });
    
    //向外导出路由模块
    module.exports = router;
    
    

中间件

  • 07局部中间件------必须在路由回调函数触发前先函数声明mw1,mw2

    const express = require("express");
    
    const app = express();
    
    const mw1 = function (req, res, next) {
      console.log("局部中间件1");
      req.a = 1;
      next();
    };
    
    const mw2 = function (req, res, next) {
      console.log("局部中间件2");
      req.b = 2;
      next();
    };
    
    //局部中间件设计-----区别于全局中间件不需要app.use()
    //而且作用范围只在当前的路由
    app.get("/", mw1, mw2, (req, res) => {
      //触发请求时先处理mw1,再响应请求
      console.log(req.a, req.b);
      res.send("index");
    });
    
    app.listen(80, () => {
      console.log("start");
    });
    
    
  • 全局中间件------在局部中间件基础上,部署全局中间件必须放到路由之前,这样才会作用全部路由

    const express = require("express");
    
    const app = express();
    
    //调用方法,快速的对外提供静态资源】
    //前一个参数是添加前缀标识,意思是需要带有abc前缀才能访问React_axioTest目录里的文件
    // (以后为了区分路由,建议带上)
    app.use("/abc", express.static("../React_axioTest"));
    
    const mw = function (req, res, next) {
      console.log("这是全局中间件1");
      req.a = 1;
      next(); //区分中间件的关键
    };
    app.use(mw); //部署全局中间件:!!!必须放到路由之前
    
    app.use(function (req, res, next) {
      console.log("这是全局中间件2");
      req.b = 2;
      next();
    }); //部署全局中间件2
    
    app.get("/a", (req, res) => {
      console.log(req.a, req.b);
      res.send("22");
    });
    
    app.listen(80, () => {
      console.log("service start");
    });
    
    
  • 09错误中间件使用------必须注册在所有路由之后

    const express = require("express");
    
    const app = express();
    
    //定义错误级别中间件,可以防止程序崩溃------四个参数,不需要next()
    //错误级别中间件必须注册在所有路由之后
    const mw = function (err, req, res, next) {
      console.log(err.message + 2222);
      res.send("error:" + err.message);
    };
    
    app.get("/a", (req, res) => {
      throw new Error("service error");
      res.send("22");
    });
    
    app.use(mw);//部署
    
    app.listen(80, () => {
      console.log("service start");
    });
    
    
  • 10内置中间件

    const express = require("express");
    
    const app = express();
    
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    
    app.post("/json", (req, res) => {
      //在服务器,可以使用req.body这个属性,来接收客户端发送过来的请求体数据
      //默认情况下,如果不配置解析表单数据的中间件,则req. body 默认等于undefined
      console.log(req.body);
      res.send("22");
    });
    
    app.post("/form", (req, res) => {
      //在服务器,可以使用req.body这个属性,来接收客户端发送过来的请求体数据
      //默认情况下,如果不配置解析表单数据的中间件,则req. body 默认等于undefined
      console.log(req.body);
      res.send("33");
    });
    
    app.listen(80, () => {
      console.log("service start");
    });
    
    
  • 11第三方中间件

    const express = require("express");
    const parser = require("body-parser");
    
    const app = express();
    
    app.use(parser.urlencoded({ extended: false }));
    
    app.post("/form", (req, res) => {
      //在服务器,可以使用req.body这个属性,来接收客户端发送过来的请求体数据
      //默认情况下,如果不配置解析表单数据的中间件,则req. body 默认等于undefined
      console.log(req.body);
      res.send("33");
    });
    
    app.listen(80, () => {
      console.log("service start");
    });
    
    
  • 12自定义解析表单数据中间件(中间件允许我们对原本属性进行修改并往下传递)

    const express = require("express");
    
    const app = express();
    
    const qs = require("querystring");
    app.use((req, res, next) => {
      //定义全局中间件业务逻辑
      // 1.定义一个str字符串,专门用来存储客户端发送过来的请求体数据
      let str = "";
      //2 监听req的data事件
      req.on("data", (chunk) => {
        str += chunk;
      });
      //3 监听req的end事件
      req.on("end", () => {
        //在str中存放的是完整的请求体数据
        console.log(str);
        //TODO  :把字符串格式请求体数据解析成对象格式
        //需要使用querystring的parse方法
        const body = qs.parse(str);
        // console.log(body);
        req.body = body;
        next();
      });
    });
    
    app.post("/form", (req, res) => {
      //在服务器,可以使用req.body这个属性,来接收客户端发送过来的请求体数据
      //默认情况下,如果不配置解析表单数据的中间件,则req. body 默认等于undefined
      console.log(req.body);
      res.send(req.body);
    });
    
    app.listen(80, () => {
      console.log("service start");
    });
    
    
  • JSONP后端写法(写在路由之前是为了不受cors中间件影响)

  • cors跨域中间件使用

    const express = require("express");
    const route = require("./router");
    const cors = require("cors");
    
    const app = express();
    //配置解析表达数据的全局中间件,处理post的body里的数据
    app.use(express.urlencoded({ extended: false }));
    
    //在cors之前配置jsonp接口,不然这个接口会被cors处理
    app.get("/jsonp", (req, res) => {
      // 获取客户端发送过来的回调函数的名字
      const funcName = req.query.callback;
      //得到要通过JSONP形式发送给客户端的数据
      const dara = { name: "sikara", age: 33 };
      //根据前两步得到的数据,拼接出一个函数调用的字符串
      const scriptStr = `${funcName}(${JSON.stringify(dara)})`;
      //   funcName()
      //把上一步拼接得到的字符串,响应给客户端的<script>标签进行解析执行
      res.send(scriptStr);
    });
    
    // 一定要在路由之前,配置cors这个中间件,从而解决接口跨域的问题
    app.use(cors());
    
    app.use("/api", route);
    
    app.listen(80, () => {
      console.log("start");
    });