Nodejs(三)-npm、express

221 阅读17分钟

一、认识 npm

  • 认识 npm

    • 一个 基于 node 环境的 包管理器
  • npm 的安装

    • 不需要安装, 只要安装了 node, 自动安装 npm
  • npm 的检测

    • 打开命令行, 目录无所谓
    • 输入指令: npm --version || npm -v
  • npm 的作用

    • 下载一切和 js 相关的 第三方
    • 相当于是一个 "软件"
    • 只不过这个 "软件" 没有 图标, 没有 UI 界面
    • 依赖 命令行 进行操作

二、npm 的基本使用

  1. npm 初始化
    • 切换到项目根目录, 打开 cmd 输入 npm init
      • package name: 项目名; 默认文件目录名 不支持中文和空格
      • version: 项目初始版本; 默认 1.0.0 通常第一版为 0.0.1 或者 0.1.0
      • description: 项目描述, 属于一段描述你这个项目的内容即可
      • entry point: 项目入口, 默认为 index.js 一般后端需要用到
      • keywords: 关键字
      • author: 作者
    • 切换到项目根目录, 打开 cmd 输入 npm init --yes || npm init -y
      • 所有选项均按照默认值配置
  2. npm 下载第三方
    • 切换到项目根目录, 输入指令 npm install 包名
    • 切换到项目根目录, 输入指令 npm i 包名
    • 下载安装后默认会多一个 package-lock.json 文件与 node_modules 文件夹
    • 下载时, 会去下载指定的第三方包, 如果第三方包用到了其他的第三方包, 会一起下载到 node_modules 中
    • 下载完毕后, 会自动记录在 package.json 中
  3. npm 查看第三方可下载版本
    • 打开 cmd, 目录无所谓
    • 输入命令: npm view 包名 versions
    • 会把该第三方包 所有的 可下载版本, 展示出来
  4. npm 下载指定版本的第三方
    • 打开 cmd, 切换到项目根目录, 输入指令 npm install 包名@版本号 || npm i 包名@版本号
    • 注意: 安装时, package 中只会记录一个, 后续安装的, 会顶替掉之前安装的
    • 版本号可以写完整版本号, 也可以写 大版本号, 会默认下载该大版本内最新的稳定版
  5. npm 删除第三方
    • 打开 cmd, 切换到项目根目录
    • 输入指令 npm unstall 包名 || npm un 包名
    • 会删除该第三方包的本地文件, 并且删除 package.json 文件内的记录
  6. npm 统一下载所有第三方
    • 打开 cmd, 切换到项目根目录
    • 输入指令 npm install || npm i
    • 注意! 项目根目录需要有 package.json
    • 会自动读取 package.json 内记录的第三方包, 一次性全部下载安装
  7. npm 清除缓存
    • 清除下载缓存
      • 打开 cmd, 目录无所谓
      • 输入指令: npm cache clear -f
    • 清除本地缓存
      • C 盘
      • 用户
      • 你的用户名
      • AppData
      • Roaming
      • npm-cache
  8. 修改镜像源地址
    • 修改 npm 第三方包的下载地址
    • 打开命令行, 目录无所谓
    • 输入指令: npm config set registry registry.npmmirror.com

三、npm 第三方包的使用

  • 在引入第三包的时候, 会先查看是否为 内置模块, 如果是, 直接导入使用, 没有的话, 检索是否为第三方包
  • 检索时, 会按照 module.path 数组内的路径, 从下标 0 开始查找, 找到就是用, 找不到就报错
const _ = require("lodash");
var objects = [{ a: 1 }, { b: 2 }];

var deep = _.cloneDeep(objects);
console.log(deep, objects);
console.log(deep[0] === objects[0]);

var object = { a: 1 };
var other = { a: 1 };
console.log(_.eq(object, object)); // true
console.log(_.eq(object, other)); // false
console.log(_.eq("a", "a")); // true

四、认识 nodemon

  • nodemon 第三方包
    • 是一个 "软件"
    • 作用: 仅仅是为了取代 node xxx.js 这个命令
  • node xxx.js 与 nodemon xxx.js 启动的区别
    • node:
      • 启动后, 如果后续有变化, 需要手动重启服务器
    • nodemon:
      • 启动后, 如果后续有变化, 保存代码后, 终端自动重启
  • nodemon 安装
    • win: npm install --global nodemon || npm i -g nodemon
    • MAC: sudo npm install --global nodemon
  • nodemon 检测
    • 打开命令行 目录无所谓
    • 输入命令 nodemon --version || nodemon -v
  • nodemon 卸载
    • win: npm uninstall --global nodemon || npm un -g nodemon
    • MAC: sudo npm uninstall --global nodemon
  • nodemon 使用
    • 和 node 运行文件的使用操作是一样的
    • 打开命令行, 切换目录到你需要执行的 JS 文件所在的目录
    • 输入指令: nodemon 文件名

五、初识 express

1699420459664(1).jpg

  • client-html,css,js(向后端发送请求)
  • controller-专门存储接口处理的函数(cart.js、user.js、goods.js)
  • router-专门存储路由相关的路由表(allRouter总表、cartRouter、userRouter、goodsRouter)
  • index.js-nodemon服务器
  • middleware
    • 内部专门存储 请求中间件
      • 比如: cart.js -> 内部专门存储 购物车相关的请求中间件
      • 比如: user.js -> 内部专门存储 用户相关的请求中间件
      • 比如: goods.js -> 内部专门存储 商品相关的请求中间件
      • ......

1.client/js/cart.js发送Ajax请求

1699355787434.jpg 2.index.js配置接口处理

1699355895718.jpg 3.router/index.js总路由表上挂载路由分表

1699355952348.jpg 4.router/cart.js路由分表上添加接口

image.png

  • 是一个 node 的第三方开发框架
    • 把启动服务器包括操作的一系列内容进行的完整的封装
    • 在使用之前, 需要下载第三方
    • 指令: npm install express

1、初识express

1. 基本搭建

/**
 *  使用 express 搭建一个服务器
 *
 *      1. 下载安装 express
 *      2. 引入 express
 *      3. 按照官方文档使用 express
 */

const express = require("express");

// 1. 创建一个服务器
const server = express();

// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));

2. 配置静态资源

  • 之前:
    • 约定:
      • 所有静态资源以 /static 开头
      • 按照后面给出的文件名自己去组装的路径
    • 组装:
      • 准备了初始目录 './client/'
      • 按照后缀去添加二级目录
      • 按照文件名去查找内容
    • 例子: /static/index.html
      • 自动去 './client/views/index.html'
  • 现在:
    • 约定:
      • 所有静态资源以 /static 开头
    • 按照 /static 后面的路径去访问指定文件
    • 要求: 在 /static 以后的内容需要按照 二级路径的正确方式书写
      • 假设你需要请求的是 './client/views/index.html' 文件
      • 你的请求地址需要书写 '/static/views/index.html'
  • 语法:
    1. express.static('开放的静态目录地址')
    2. server.use('访问这个地址的时候', 去到开放的静态目录地址)
const express = require("express");

// 1. 创建一个服务器
const server = express();

/**
 *  1.1 引入静态资源
 * 
 *      原本:
 *          要求前端访问的时候 只要是静态资源 固定以 /static 开头
 *              后续跟上要访问的文件名
 * 
 *          我们 首先判断 请求是不是以 /static 开头
 *          然后根据文件后缀决定去 views/css/js 中寻找文件
 *          最终根据文件名, 去到对应文件夹中, 找到对应的文件, 读取成功后 将数据反馈给请求者(浏览器或者某一个标签)
 *              示例:
 *                  /static/index.html
 *                  /static/list.js
 *                  /static/login.css
 * 
 *      现在:
 *          注意: 我们目前使用的是框架, 框架中必然会出现很多便捷的方法, 有可能之前的10行代码, 现在 1行就够了
 * 
 *      所以在当前框架中, 我们需要有一个新的约定
 *          所有的前端请求静态资源的时候, 统一 /static 开头
 *              然后后续跟上文件的路径
 *                  /static/views/index.html
 *                  /static/js/list.js
 *                  /static/css/login.css
*/

server.use('/static', express.static('./client'))
/**
 *  当前只要有一个请求是以 /static 开头的
 *      比如说:
 *                  /static/views/index.html
 *                  /static/js/list.js
 *                  /static/css/login.css
 * 
 *      然后会被转接到 ./client 目录中去
 * 
 *      所以 框架处理完毕后 上述的 url 最终是:
 *                  ./client/views/index.html
 *                  ./client/js/list.js
 *                  ./client/css/login.css
*/

// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));

3. 配置服务器接口

const express = require("express");

// 1. 创建一个服务器
const server = express();

// 1.1 引入静态资源
server.use("/static", express.static("./client"));

// 1.2 配置接口处理

// 商品列表
server.get('/api/goods/list', (req, res) => {
    // res.end(JSON.stringify({
    //     code: 1,
    //     msg: '请求成功'
    // }))


    // 在 express 框架中我们需要结束请求的时候, 可以使用 send 方法, 内部传递的数据会被转换为 JSON 格式的字符串
    res.send({
        code: 1,
        msg: '商品列表请求成功'
    })
})

// 商品详情
server.post('/api/goods/info', (req, res) => {
    res.send({
        code: 1,
        msg: '商品详情请求成功'
    })
})

// 登录
server.post('/api/user/login', (req, res) => {
    res.send({
        code: 1,
        msg: '登陆成功',
        token: '登陆成功给的 token'
    })
})

// 购物车列表
server.get('/api/cart/list', (req, res) => {
    res.send({
        code: 1,
        msg: '购物车列表请求成功'
    })
})

// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));

4.添加controller

  • 内部专门存储接口处理的函数
  • 当前文件夹内按照接口的分类, 创建对应的文件
    • 比如: cart.js -> 内部专门存储 购物车相关的接口处理函数
    • 比如: user.js -> 内部专门存储 用户相关的接口处理函数
    • 比如: goods.js -> 内部专门存储 商品相关的接口处理函数
    • .....

1.controlle文件夹中的其中一个cart

    // 购物车列表
exports.cartList = (req, res) => {
    res.send({
        code: 1,
        msg: "购物车列表请求成功",
    });
};

// 购物车内添加商品
exports.cartAddItem = (req, res) => {
    res.send({
        code: 1,
        msg: "购物车添加成功",
    });
};

// 购物车内删除商品
exports.cartDelItem = (req, res) => {
    res.send({
        code: 1,
        msg: "删除成功",
    });
};

2.index.js

    /**
 *  使用 express 搭建一个服务器
 *
 *      1. 下载安装 express
 *      2. 引入 express
 *      3. 按照官方文档使用 express
 */

const express = require("express");
const { goodsList, goodsInfo } = require("./controller/goods");
const { cartList, cartAddItem, cartDelItem } = require("./controller/cart");
const { userLogin, userInfo } = require("./controller/user");

// 1. 创建一个服务器
const server = express();

// 1.1 引入静态资源
server.use("/static", express.static("./client"))

// 1.2 配置接口处理

// 商品相关
server.get("/api/goods/list", goodsList);
server.post("/api/goods/info", goodsInfo);

// 购物车相关
server.get("/api/cart/list", cartList);
server.get("/api/cart/addItem", cartAddItem);
server.get("/api/cart/delItem", cartDelItem);

// 用户相关
server.post("/api/user/login", userLogin);
server.get("/api/user/info", userInfo);

// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));

2、路由表

  • router
    • 内部专门存储路由相关的路由表
      • 比如: cart.js -> 内部专门存储 购物车相关的路由表
      • 比如: user.js -> 内部专门存储 用户相关的路由表
      • 比如: goods.js -> 内部专门存储 商品相关的路由表
      • 比如: index.js -> 内部专门存储 路由总表

1.路由总表

    // 0. 导入 express
const express = require("express");
// 0. 导入 所有的路由分表
const { goodsRouter } = require("./goods");
const { userRouter } = require("./user");
const { cartRouter } = require("./cart");

// 1. 创建一个 路由总表
const allRouter = express.Router();

// 2. 向路由总表上 挂载一些 路由分表
allRouter.use("/goods", goodsRouter);
allRouter.use("/cart", cartRouter);
allRouter.use("/user", userRouter);

// 3. 导出路由总表, 给服务器使用
exports.allRouter = allRouter;

2.路由分表(以购物车为例)

    // 内部存储购物车相关的路由分表

const express = require("express");
const { cartList, cartAddItem, cartDelItem } = require("../controller/cart");

// 1. 创建一张路由分表
const cartRouter = express.Router();

// 2. 向路由分表上添加一些接口
cartRouter.get("/list", cartList);
cartRouter.get("/addItem", cartAddItem);
cartRouter.get("/delItem", cartDelItem);

// 3. 导出当前路由分表, 给路由总表使用
exports.cartRouter = cartRouter;

3.index.js

const express = require("express");
const { allRouter } = require("./router");
/**
 *  如果需要导入的文件时某文件夹内的 XXX.js
 *
 *      1. 文件后缀 .js 可以省略
 *      2. 文件名是 index 的时候 文件名也可以省略
 *
 *
 *      require("./router")     =>      require("./router/index")           =>      require("./router/index.js")
 */

// 1. 创建一个服务器
const server = express();

// 1.1 引入静态资源
server.use("/static", express.static("./client"));

// 1.2 配置接口处理
server.use("/api", allRouter);

// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));

3、中间件

  • 中间件的分类
      1. 全局中间件
      • 服务器.use(参数1, 参数2)
        • 参数1: 是表示以什么路径开头
        • 参数2: 如果路径的开头符合 参数1 的要求, 那么执行参数2 的代码
        • 参数1 可以不传递
      1. 路由中间件
      • 路由表.use(参数1, 参数2)
        • 参数1: 是表示以什么路径开头
        • 参数2: 如果路径的开头符合 参数1 的要求, 那么执行参数2 的代码
        • 参数1 可以不传递
      1. 请求中间件
      • 在 请求的处理函数前, 在书写一个 函数
      1. 全局错误处理中间件

1、全局中间件

    const express = require("express");
const { allRouter } = require("./router");
const fs = require("fs");

// 1. 创建一个服务器
const server = express();

/**
 *  后续新增功能: 将每一次请求, 记录到 隔壁的 index.txt 文件
 *
 *      因为每一次请求进入到对应的 静态资源 或者 接口处理后, 就不会再触发后续的代码了
 *
 *      所以当前的全局中间件, 必须书写在 1.1 和 1.2 之前
 * 
 * 
 *      每一个自定义的中间件, 进入后请求到此暂时中断, 需要我们指定是否继续向下运行
 *      如果需要向下运行, 那么需要借助当前函数的第三个形参, 这个形参是一个函数, 当你调用之后, 就会向下运行到下一个环节
 */
server.use((req, res, next) => {
    fs.appendFile(
        "./index.txt",
        `时间: ${new Date()} ---> 请求地址: ${req.url} \n`,
        () => next()
    );
});

// 1.1 引入静态资源
server.use("/static", express.static("./client"));

// 1.2 配置接口处理
server.use("/api", allRouter);

// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));

2、路由中间件(以购物车为例)

1.router中cart.js

    // 内部存储购物车相关的路由分表
const express = require("express");
const { cartList, cartAddItem, cartDelItem } = require("../controller/cart");

// 1. 创建一张路由分表
const cartRouter = express.Router();

// 1.1 因为当前的 购物车接口全都需要登陆过才能使用, 所以我们将 token 的校验, 添加到 路由中间件中
cartRouter.use((req, res, next) => {
    if (req.headers.authorization === "10086") {
        /**
         *  当前 分支能够执行, 说明按照我们目前的约定 token 一定没有问题
         *  那么我们就不再做其他的处理, 让请求继续向下运行即可
        */
        next()
    } else if (req.headers.authorization === "10010") {
        res.send({
            code: 0,
            msg: "token 过期, 请重新登陆获取最新的 token",
        });
    } else if (req.headers.authorization === undefined) {
        res.send({
            code: 0,
            msg: "您没有传递 token, 请正确传递 token",
        });
    } else {
        res.send({
            code: 0,
            msg: "token 不正确",
        });
    }
});

// 2. 向路由分表上添加一些接口
cartRouter.get("/list", cartList);
cartRouter.get("/addItem", cartAddItem);
cartRouter.get("/delItem", cartDelItem);

// 3. 导出当前路由分表, 给路由总表使用
exports.cartRouter = cartRouter;

2.client中的cart.js

    // 获取购物车列表
getCartList();
function getCartList() {
    const xhr = new XMLHttpRequest();
    xhr.open(
        "GET",
        "http://localhost:8080/api/cart/list?userid=10086&current=1&pagesize=8"
    );
    /**
     *  目前我们因为没有token, 所以暂定 10086 是真正的 token
     * 
     *      10010 是 过期的token
     *      其他的是伪造的 token
    */
    xhr.setRequestHeader('authorization', '10086')
    xhr.send();
    xhr.onload = function () {
        const res = JSON.parse(xhr.responseText);
        console.log(res);
    };
}

// 添加购物车
addItem();
function addItem() {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://localhost:8080/api/cart/addItem");
    xhr.setRequestHeader('authorization', '10010')
    xhr.send();
    xhr.onload = function () {
        const res = JSON.parse(xhr.responseText);
        console.log(res);
    };
}

// 删除购物车
delItem();
function delItem() {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://localhost:8080/api/cart/delItem");
    xhr.setRequestHeader('authorization', 'QF001')
    xhr.send();
    xhr.onload = function () {
        const res = JSON.parse(xhr.responseText);
        console.log(res);
    };
}

3、请求中间件(购物车为例)

  • middleware
    • 内部专门存储 请求中间件
      • 比如: cart.js -> 内部专门存储 购物车相关的请求中间件
      • 比如: user.js -> 内部专门存储 用户相关的请求中间件
      • 比如: goods.js -> 内部专门存储 商品相关的请求中间件
      • ......

1.router-cart.js

const express = require("express");
const { cartList, cartAddItem, cartDelItem } = require("../controller/cart");
const {
    cartListMid,
    cartAddItemMid,
    cartDelItemMid,
} = require("../middleware/cart");

// 创建一个 路由分表
const Router = express.Router();

// 路由中间件
Router.use((req, res, next) => {
    if (req.headers.authorization === "10086") {
        next();
    } else if (req.headers.authorization === "10010") {
        res.send({
            code: 0,
            msg: "token 过期",
        });
    } else if (req.headers.authorization === undefined) {
        res.send({
            code: 0,
            msg: "您没有传递 token",
        });
    } else {
        res.send({
            code: 0,
            msg: "token 不正确",
        });
    }
});

// 向路由分表上添加一些接口
Router.get("/list", cartListMid, cartList);
Router.get("/addItem", cartAddItemMid, cartAddItem);
Router.get("/delItem", cartDelItemMid, cartDelItem);

// 将路由分表导出, 给路由总表使用
exports.cartRouter = Router;

2.middleware

    exports.cartListMid = (req, res, next) => {
    /**
     *  1. 判断用户有没有传递 用户ID, 并且去数据库查询有没有对应的ID
     *
     *      在 express 框架中, 一个接口的请求报文中的参数, 会被 express 解析到 req.query 中
     *
     *      但是注意, 只有 get 请求会被解析, post 请求 不会被解析, post 需要我们像以前写原生服务器一样, 自己解析
     */
    // console.log(req.query);

    if (req.query.userid === undefined) {
        return res.send({
            code: 0,
            msg: "参数不够",
        });
    }

    next();
};

exports.cartAddItemMid = (req, res, next) => {
    // 1. 判断用户有没有传递 用户ID 和 商品ID
    const { userid, goodsid } = req.query;

    if (!userid || !goodsid) {
        return res.send({
            code: 0,
            msg: "参数不够",
        });
    }

    next();
};

exports.cartDelItemMid = (req, res, next) => {
    // 1. 判断用户有没有传递 用户ID 和 商品ID
    const { userid, goodsid } = req.query;

    if (!userid || !goodsid) {
        return res.send({
            code: 0,
            msg: "参数不够",
        });
    }

    next();
};

4、全局错误处理中间件

1699421154814.jpg

  • 全局错误处理中间件有一个固定的位置, 一定是在服务器文件的最后

1.index.js

    const express = require("express");
const { allRouter } = require("./router");
const fs = require("fs");

// 创建服务器
const server = express();

// 全局中间件
server.use((req, res, next) => {
    fs.appendFile(
        "./index.txt",
        `时间: ${new Date()} ---> 请求地址: ${req.url} \n`,
        () => next()
    );
});

// 配置静态资源
server.use("/static", express.static("./client"));

// 配置接口处理
server.use("/api", allRouter);

// 全局错误处理中间件有一个固定的位置, 一定是在服务器文件的最后
server.use((err, req, res, next) => {
    /**
     *  当前中间件只是为了将我们的错误 放在一个统一处理的地方
     *
     *      错误:
     *          token 过期
     *          token 不正确
     *          token 没有传递
     *          参数 不够
     *          参数 传递的不正确
     *          ......
     *
     *      我们可以给这些预估的错误 约定一个编号
     *          将来在其他位置的时候遇到了某一个错误
     *          我们直接将当前的请求跳转到 这个错误处理中间件
     *          并且根据错误的编号, 做出不同的反馈
     *
     *      这里我们和我们项目的所有后端开发人员做一个约定
     *          编号:
     *              token 过期              1
     *              token 不正确            2
     *              token 没有传递          3
     *              参数 不够               4
     *              参数 传递的不正确        5
     *              ......
     */

    if (err === 1) {
        res.send({
            code: 0,
            msg: "token 过期",
        });
    } else if (err === 2) {
        res.send({
            code: 0,
            msg: "token 不正确",
        });
    } else if (err === 3) {
        res.send({
            code: 0,
            msg: "您没有传递 token",
        });
    } else if (err === 4) {
        res.send({
            code: 0,
            msg: "参数不够",
        });
    } else if (err === 5) {
        res.send({
            code: 0,
            msg: "参数不正确",
        });
    }
});

// 配置端口号
server.listen(8080, () => console.log("服务器启动成功"));

2.router/cart.js

    const express = require("express");
const { cartList, cartAddItem, cartDelItem } = require("../controller/cart");
const {
    cartListMid,
    cartAddItemMid,
    cartDelItemMid,
} = require("../middleware/cart");

// 创建一个 路由分表
const Router = express.Router();

// 路由中间件
Router.use((req, res, next) => {
    if (req.headers.authorization === "10086") {
        next();
    } else if (req.headers.authorization === "10010") {
        next(1);
    } else if (req.headers.authorization === undefined) {
        next(3);
    } else {
        next(2);
    }
});

// 向路由分表上添加一些接口
Router.get("/list", cartListMid, cartList);
Router.get("/addItem", cartAddItemMid, cartAddItem);
Router.get("/delItem", cartDelItemMid, cartDelItem);

// 将路由分表导出, 给路由总表使用
exports.cartRouter = Router;

3、middleware/cart.js

    exports.cartListMid = (req, res, next) => {
    /**
     *  1. 判断用户有没有传递 用户ID, 并且去数据库查询有没有对应的ID
     *
     *      在 express 框架中, 一个接口的请求报文中的参数, 会被 express 解析到 req.query 中
     *
     *      但是注意, 只有 get 请求会被解析, post 请求 不会被解析, post 需要我们像以前写原生服务器一样, 自己解析
     */
    // console.log(req.query);

    if (req.query.userid === undefined) {
        // return res.send({
        //     code: 0,
        //     msg: "参数不够",
        // });
        return next(4)
    }

    next();
};

exports.cartAddItemMid = (req, res, next) => {
    // 1. 判断用户有没有传递 用户ID 和 商品ID
    const { userid, goodsid } = req.query;

    if (!userid || !goodsid) {
        // return res.send({
        //     code: 0,
        //     msg: "参数不够",
        // });
        return next(4)
    }

    next();
};

exports.cartDelItemMid = (req, res, next) => {
    // 1. 判断用户有没有传递 用户ID 和 商品ID
    const { userid, goodsid } = req.query;

    if (!userid || !goodsid) {
        // return res.send({
        //     code: 0,
        //     msg: "参数不够",
        // });
        return next(4)
    }

    next();
};

5、解析请求参数

1.index.js(利用全局中间件)

image.png

    const express = require("express");
const { allRouter } = require("./router");
const fs = require("fs");
const url = require('url')

// 创建服务器
const server = express();

// 全局中间件
server.use((req, res, next) => {
    fs.appendFile(
        "./index.txt",
        `时间: ${new Date()} ---> 请求地址: ${req.url} \n`,
        () => next()
    );
});

// 配置静态资源
server.use("/static", express.static("./client"));

// 添加一个全局中间件, 用于处理 post 方式的请求参数
server.use((req, res, next) => {
    if (req.method === "GET") return next();

    // 但代码运行到这个位置的时候, 说明一定是 post 方式的请求
    let dataStr = "";
    req.on("data", (chunk) => (dataStr += chunk));

    req.on("end", () => {
        if (req.headers["content-type"] === "application/json") {
            dataStr = JSON.parse(dataStr);
        }

        if (
            req.headers["content-type"] === "application/x-www-form-urlencoded"
        ) {
            dataStr = url.parse("?" + dataStr, true).query;
        }

        req.body = dataStr

        next()
    });
});

// 配置接口处理
server.use("/api", allRouter);

// 全局错误处理中间件有一个固定的位置, 一定是在服务器文件的最后
server.use((err, req, res, next) => {
    if (err === 1) {
        res.send({
            code: 0,
            msg: "token 过期",
        });
    } else if (err === 2) {
        res.send({
            code: 0,
            msg: "token 不正确",
        });
    } else if (err === 3) {
        res.send({
            code: 0,
            msg: "您没有传递 token",
        });
    } else if (err === 4) {
        res.send({
            code: 0,
            msg: "参数不够",
        });
    } else if (err === 5) {
        res.send({
            code: 0,
            msg: "参数不正确",
        });
    }
});

// 配置端口号
server.listen(8080, () => console.log("服务器启动成功"));

2. body-parser

  • 在 node 中有一个第三方包 专门帮我们解析 post 的参数, 我们下载/引入/使用 即可;但是 express 依赖了这个第三方包, 所以你安装 express 的时候会自动安装这个第三方包
    const express = require("express");
const { allRouter } = require("./router");
const fs = require("fs");
const bodyParser = require('body-parser')


/**
 *  在 node 中有一个第三方包 专门帮我们解析 post 的参数, 我们下载/引入/使用 即可
 * 
 *  这个包叫做: body-parser
 * 
 *  但是 express 依赖了这个第三方包, 所以你安装 express 的时候会自动安装这个第三方包
*/

// 创建服务器
const server = express();

// parse application/x-www-form-urlencoded
server.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
server.use(bodyParser.json())

// 全局中间件
server.use((req, res, next) => {
    fs.appendFile(
        "./index.txt",
        `时间: ${new Date()} ---> 请求地址: ${req.url} \n`,
        () => next()
    );
});

// 配置静态资源
server.use("/static", express.static("./client"));

// 配置接口处理
server.use("/api", allRouter);

// 全局错误处理中间件有一个固定的位置, 一定是在服务器文件的最后
server.use((err, req, res, next) => {
    if (err === 1) {
        res.send({
            code: 0,
            msg: "token 过期",
        });
    } else if (err === 2) {
        res.send({
            code: 0,
            msg: "token 不正确",
        });
    } else if (err === 3) {
        res.send({
            code: 0,
            msg: "您没有传递 token",
        });
    } else if (err === 4) {
        res.send({
            code: 0,
            msg: "参数不够",
        });
    } else if (err === 5) {
        res.send({
            code: 0,
            msg: "参数不正确",
        });
    }
});

// 配置端口号
server.listen(8080, () => console.log("服务器启动成功"));