node学习笔记

文章目录

  • 一、初识
    • Node.js 定义
    • Node.js 中的 JS 运行环境
    • Node.js 作用
    • 学习路径
    • Node.js 执行 JavaScript 代码
  • 二、文件系统模块
  • 三、path 路径模块
  • 四、http 模块
  • 五、模块化
    • (一)、模块化基础
      • 模块化定义
      • 模块化好处
      • 模块的使用
      • 模块作用域
    • (二)、Node.js 模块的三大分类
      • 内置模块
      • 自定义模块
      • 第三方模块
    • (三)、向外共享模块作用域中的成员
      • module 对象
      • module.exports 对象
      • exports 对象
    • (四)、Node.js 模块化规范
    • (五)、npm 管理包
      • 包:
      • npm
      • 包管理配置文件
      • 解决包下载速度慢
        • nrm
      • 包的分类
      • 规范的包结构
    • (六)、开发属于自己的包
        • 步骤
    • (七)、模块的加载机制
  • 六、Express
    • (一)、Express 基础
      • 定义
      • 基本使用——创建 web 服务器
      • 托管静态资源
      • nodemon
    • (二)、Express 路由
      • 基础知识
      • 路由的使用
    • (三)、中间件
      • 基础知识
      • 全局生效的中间件
      • 局部生效的中间件
      • 中间件的使用注意事项
      • 中间件的分类
        • 应用级别的中间件
        • 路由级别的中间件
        • 错误级别的中间件
        • Express 内置的中间件
        • 第三方的中间件
      • 自定义中间件
    • (四)、使用 Express 编写接口
      • 编写 GET 接口
      • 编写 POST 接口
      • CORS 跨域资源共享
      • JSONP 接口
  • 七、数据库与身份认证
    • (一)、数据库的基本概念
      • 常见的数据库
      • 关系型数据库的数据组织结构
    • (二)、安装并配置 MySQL
      • 安装的软件
    • (三)、MySQL 的基本使用
    • (四)、在 Expres 中操作 MySQL
      • 步骤
      • 通过 mysql 模块执行 SQL 语句
    • (五)、前后端的身份认证
      • 分类
      • Session
        • cookie
        • cookie 在身份认证中的作用
        • cookie 不具有安全性
        • Session 工作原理
        • 在 Express 中使用 Session

一、初识

Node.js 定义

Node.js 是一个基于 V8 引擎的 JavaScript 运行时(运行环境)

Node.js 中的 JS 运行环境

  • V8 引擎
  • 内置 API
    • fs
    • path
    • http
    • js 内置对象
    • querystring
    • 等等

** 注意:**
浏览器是 JavaScript 的前端运行环境
Node.js 是 JavaScript 的后端运行环境
Node.js 中无法调用 DOM、BOM 等浏览器的 API

Node.js 作用

基于 Node.js 有很多强大的工具和框架
① Express—Web 应用
② Electron—跨平台的桌面应用
③ restify—快速构建 API 接口
④ 读写操作数据库、创建实用的命令行工具辅助前端开发
⑤ 等等

学习路径

  • 基础语法
  • 内置 API
  • express、数据库

Node.js 执行 JavaScript 代码

  1. 在终端进入 js 文件目录
  2. node 文件名

二、文件系统模块

  • readFile
  • writeFile

** 注意:**

  • 动态路径拼接
    • __dirname:表示当前文件所处的目录

三、path 路径模块

  1. 拼接路径:path.join([…path])
  2. 查看文件名:path.basename(path[,ext])
  3. 查看文件后缀:path.extname(path)

四、http 模块

  1. 创建基本的 web 服务器
// 1.引入http模块
const http = require("http");
// 2.创建服务器
const server = http.createServer();
// 3.监听request事件
server.on("request", (req, res) => {
  // 3.1 req是请求对象,包含与客户端相关的数据与属性
  // 如:req.url:客户端请求的地址;req.method:请求类型
  const url = req.url;
  const method = req.method;
  // 3.2 res是相应对象,包含与服务端相关的数据与属性
  // 如:res.end(str):向客户端发送指定的内容并结束这次请求的处理过程
  res.setHeader('Content-Type','text/html; charset=utf-8')
  res.end('hello')
});
// 4.启动服务器
server.listen(8080, () => {
  console.log("http server running at http://127.0.0.1:8080");
});

五、模块化

(一)、模块化基础

模块化定义

解决一个复杂问题时,自顶向下把系统分成若干模块的过程。
对于整个系统来说,模块是课组合、分解和更换的单元。

模块化好处

  1. 提高了代码的复用性
  2. 提高了代码的可维护性
  3. 可实现按需加载

模块的使用

  1. 加载模块:
  • require()

模块作用域

和函数作用域类似,只能再当前模块内被访问。
防止全局变量的污染。

(二)、Node.js 模块的三大分类

内置模块

内置模块是 Node.js 官方提供的。
例如:fs,path,http 等等。

自定义模块

用户自己创建的.js 文件。

第三方模块

由第三方开发出来的模块,使用前需要先下载。
第三方模块也叫做包。

(三)、向外共享模块作用域中的成员

module 对象

在每个.js 自定义模块中都有一个 module 对象,它存储了和当前模块有关的信息.
打印 module 的一个例子

Module {
  id: '.',
  path: 'E:\\工作\\node学习',
  exports: {},
  filename: 'E:\\工作\\node学习\\1.js',
  loaded: false,
  children: [],
  paths: [
    'E:\\工作\\node学习\\node_modules',
    'E:\\工作\\node_modules',
    'E:\\node_modules'
  ]
}

module.exports 对象

将模块内的成员共享出去,供外界使用。默认情况为{}
外界用 require()方法导入自定义模块时,得到的就是 module.exports 这个对象。

exports 对象

exports 指向的就是 module.exports 这个对象。
** 注意:**
将模块导出的对象始终为 module.exports 这个对象。

(四)、Node.js 模块化规范

Node.js 遵循了 CommonJS 模块化规范。
规定:

  1. 每个模块内部,module 变量代表当前模块。
  2. module 变量是一个对象,他的 exports 属性(即 module.exports)是对外的接口。
  3. 加载某个模块,其实就是加载该模块的 module.exports 属性。require()方法用于加载模块。

(五)、npm 管理包

包:

即第三方模块。包是基于内置模块封装出来的,提供了更高级、更方便的 API,极大的提高了开发效率。
https://www.npmjs.com/ 查看包 https://registry.npmjs.org/ 下载包

npm

随着 Node.js 安装包一起安装。

  • 下载
    npm install 包名称
    简写:
    npm i 包名称
  • 卸载
    npm uninstall 包名称

初次安装包出现的文件:

  • node_modules:
    存放所有已安装到项目中的包
  • package-lock.json:
    记录 node_modules 目录下每个包的下载信息
    这两个文件不要修改操作。npm 会自动管理。

包管理配置文件

npm 规定,在项目根目录中,必须提供一个叫做 package.json 的包管理配置文件。
package.json:记录与项目有关的一些配置信息。
例如:

  • 项目的名称、版本号、描述等等
  • 项目中的包
  • 哪些包只在开发期间用到
  • 哪些包在开发和部署时都要用到
    如何快速创建 package.json:
    npm init -y
  1. dependencies
    只在项目开发阶段用到的包
  2. devDependencies
    在开发和上线都需要用到的包
    npm i 包名 -D
    等同于
    npm install 包名 --save-dev

解决包下载速度慢

淘宝 NPM 镜像服务器

  • 检查当前的下载包镜像源
    npm config get registry
  • 将下载包的镜像源切换为淘宝镜像
    npm config set registry=https://registry.npm.taobao.org/
  • 检查镜像源是否下载成功
    npm config get registry
nrm

nrm 是用来切换镜像源的

  • 安装
    npm i nrm -g
    (-g 安装到全局)
  • 查看所有的镜像源
    nrm ls
  • 将下包的镜像源切换到 taobao 镜像
    nrm use taobao

包的分类

  1. 项目包
  • 开发依赖包:
    npm i 包名
    在 package.json 的 dependencies 的节点下
  • 核心依赖包:
    npm i 包名 -D
    在 package.json 的 devDependencies 的节点下
  1. 全局包:
    npm i 包名 -g
    (一般在 C 盘\用户\用户名\AppData\Roaming\npm\node_modules)

规范的包结构

  1. 包必须以单独的目录而存在
  2. 包的顶级目录下必须包含 package.json 这个包管理配置文件
  3. package.json 中必须包含 name(包的名字)、version(版本号)、main(包的入口)

(六)、开发属于自己的包

一个例子——包含有的功能:

  • 格式化日期
// 1.导入
const tools = require("./sunny-tools");
// 2.使用
const dt = tools.dateFormat(new Date());
console.log(dt);
  • 转义 HTML 中的特殊字符
// 1.导入
const tools = require("./sunny-tools");
// 2.使用
const htmlStr = '

你好小黄 

'; const str = tools.htmlEscape(htmlStr); console.log(str);
  • 还原 HTML 中的特殊字符
// 1.导入
const tools = require("./sunny-tools");
// 2.使用
const rawHTML = tools.htmlUnEscape(str);
console.log(rawHTML);
步骤
  1. 初始化包的结构
    ① 新建 sunny-tools 文件
    ② 在 sunny-tools 文件中新建:

    • package.json(包管理配置文件)
    • index.js(包的入口文件)
    • README.md(包的说明文档)

    ③ 在 sunny-tools 文件中新建 src 文件夹,再在 src 中新建:

    • dateFormat(转换时间的模块)
    • htmlEscape(有关 HTML 字符转义模块)
  2. 初始化 package.json 文件

{
  "name":"sunny-tools",
  "version":"1.0.0",
  "main":"index.js",
  "description": "提供了格式化时间,HTMLEscape的功能",
  "keywords": ["sunny","dataFomat","escape"],
  "license": "ISC"
}
  1. 初始化 index.js
const date = require("./src/dateFormat");
const escape = require("./src/htmlEscape");
module.exports = {
  ...date,
  ...escape,
};
  1. 编写 dateFormat
function dateFormat(dataStr) {
  const dt = new Date(dataStr);
  const y = dt.getFullYear();
  const m = padZero(dt.getMonth() + 1);
  const d = padZero(dt.getDay());
  const hh = padZero(dt.getHours());
  const mm = padZero(dt.getMinutes());
  const ss = padZero(dt.getSeconds());
  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
// 补零函数
function padZero(n) {
  return n > 9 ? n : "0" + n;
}
module.exports = {
  dateFormat,
};
  1. 编写 htmlEscape
// 转义HTML字符
function htmlEscape(htmlstr) {
  return htmlstr.replace(/<|>|"|&/g, (match) => {
    switch (match) {
      case "<":
        return "<";
      case ">":
        return ">";
      case '"':
        return """;
      case "&":
        return "&";
    }
  });
}

// 还原HTML字符
function htmlUnEscape(str) {
  return str.replace(/<|>|"|&/g, (match) => {
    switch (match) {
      case "<":
        return "<";
      case ">":
        return ">";
      case """:
        return '"';
      case "&":
        return "&";
    }
  });
}
module.exports = {
  htmlEscape,
  htmlUnEscape,
};

  1. 编写包的说明文档
  • 安装方式
  • 导入方式
  • 格式化时间
  • 转义 HTML 特殊字符
  • 还原 HTML 字符
  • 开源协议
  1. 发布
  • 注册 npm 帐号
    ① 访问https://www.npmjs.com/
    ② 注册
    ③ 一定要点击发给邮箱的验证链接
  • 在终端登录 npm 帐号
    ** 注意: **
    登录前一定要将镜像切换到官方即 npm
//查看所有的镜像源
nrm ls
//将下包的镜像源切换到 npm 镜像
nrm use npm
npm login
//根据提示输入用户名、密码
  • 发布包
    切换到发布包的根目录下(包名要唯一)
    npm publish

  • 删除已发布的包
    npm unpublish 包名 --force

(七)、模块的加载机制

  1. 优先从缓存中加载
    模块在第一次加载后会被缓存
    多次调用相同的 require(),不会被执行多次
  2. 内置模块的加载机制
    优先级最高
  3. 自定义模块加载机制
  • 必须指定已./../的路径表示符。如果没有则 node 把它当作内置模块或者第三方模块加载。
  • 如果省略了文件扩展名,node 按以下顺序尝试加载:
    ① 补全.js
    ② 补全.json
    ③ 补全.node
    ④ 加载失败,报错
  1. 第三方模块加载机制
    从当前模块的父目录开始,从/node_modules 加载
    如果没有找到,在上一层父级的/node_modules 中加载
    直到文件系统的根目录
  2. 目录作为模块
    ① 在加载的目录下找 package.json 中找 main 属性,作为 require()加载入口
    ② 没有 ①,尝试加载 index.js
    ③ 没有 ①②,终端报错

六、Express

(一)、Express 基础

定义

基于 Node.js 平台,快速、开放、极简的 Web 开发框架。
通俗:Express 和 Node.js 内置的 http 模块类似,专门用来创建 Web 服务器
下载 express
npm install express

基本使用——创建 web 服务器

  1. 创建基本的 web 服务器
// 1. 导入express
const express = require("express");
// 2. 创建 web 服务器
const app = express();
// 3. 调用app.listen(端口号,启动成功的回调函数),启动服务器
app.listen(80, () => {
  console.log("express server running at http://172.0.0.1");
});

  1. 监听 GET 请求
    app.get():
  • 参数 1:URL 地址
  • 参数 2:对应的处理函数
    • req:请求对象
    • res:响应对象
  1. 监听 POST 请求
    app.post():
  • 参数 1:URL 地址
  • 参数 2:对应的处理函数
    • req:请求对象
    • res:响应对象
  1. 把内容响应给客户端
    res.send()
    参数可为 json 对象,也可以为文本

托管静态资源

  1. express.static()
    express.static()创建一个静态资源服务器

app.use(express.static('public'))

现在可以访问 public 目录下所有文件(假设 public 有 css.js,index.js,index.html)
http://localhost:3000/css.js
http://localhost:3000/index.js
http://localhost:3000/index.html
例子:

const express = require("express");
const app = express();
app.use(express.static("./clock"));
app.listen(80, () => {
  console.log("express server running at http://127.0.0.1");
});

  1. 托管多个静态资源目录
    多次调用 express.static()就可以
    注意:
    如果多个静态资源目录下有相同的文件时,则按顺序加载(即访问的是第一个)
    例子:
const express = require("express");
const app = express();
app.use(express.static("./files"));
app.use(express.static("./clock"));

app.listen(80, () => {
  console.log("express server running at http://127.0.0.1");
});
//files和clock文件下都有clock.html
//访问http://127.0.0.1/clock.html   出现的是files下的clock.html
  1. 挂载路径前缀
    app.use('/public',express.static('public'))
    现在可以访问 public 目录下所有文件(假设 public 有 css.js,index.js,index.html)
    http://localhost:3000/public/css.js
    http://localhost:3000/public/index.js
    http://localhost:3000/public/index.html

nodemon

下载
npm i -g nodemon
使用
原来是node app.js,下载改为
nodemon app.js

(二)、Express 路由

基础知识

  1. 路由的定义
    路由:广义上,路由就是映射关系
  2. express 中的路由
  • 路由:客户端的请求与服务器处理函数之间的映射关系
  • 组成:请求的类型、请求的 URL 地址、处理函数
    app.METHOD(PATH,HANDLER)
  • 例子:
    app.get("/user", (req, res) => {
    res.send({ name: "zs", age: 20, gender: "男" });
    });
    app.post("/user", (req, res) => {
    res.send("请求成功");
    });
    
  • 路由的匹配过程:
    • 每当一个请求到达服务器之后,需要经过路由的匹配,只有匹配成功之后才会调用对应的处理函数
    • 在匹配时,会按照路由的顺序进行匹配,如果请求的类型和请求的 URL 同时匹配成功,则 Express 会将这次请求转发交给对应得函数进行处理

路由的使用

  1. 最简单的路由使用
    不常用
    在 express 中使用路由最简单的方式就是把路由挂载到 app 上,示例:
// 1. 导入express
const express = require("express");
// 2. 创建 web 服务器
const app = express();
//挂载路由
app.get("/", (req, res) => {
  res.send('hello');
});
app.post("/", (req, res) => {
  res.send("请求成功");
});
// 3. 调用app.listen(端口号,启动成功的回调函数),启动服务器
app.listen(80, () => {
  console.log("express server running at http://127.0.0.1");
});

  1. 模块化路由
    将路由抽离为单独的模块,步骤:
  • 创建路由模块对应的.js 文件
  • 调用express.Router()函数创建路由对象
  • 向路由对象上挂载具体的路由
  • 使用 module.exports 向外共享路由对象
  • app.use()函数注册路由模块

① 创建路由模块

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

② 注册路由模块

//1.到哦如路由模块
const userRouter = require(./ruoter/user.js)
2.使用app.use()注册路由模块
app.use(userRouter)
  1. 为路由模块添加前缀
    类似于托管静态资源,为静态资源统一挂载访问前缀一样,路由模块添加前缀的方式也非常简单:
    //1.到哦如路由模块
    const userRouter = require(./ruoter/user.js)
    2.使用app.use()注册路由模块
    app.use('/api',userRouter)
    

(三)、中间件

基础知识

  1. 定义:
    中间件就是流程中的中间处理环节。
  2. Express 中间件的调用流程
    当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
  3. Express 中间件的格式
    中间件本质上就是一个 function 处理函数
const express = require("express");
const app = express();

app.get("/", function(req,res,next){
  next()
});

app.listen(3000);

注意:
中间件函数的形参列表中必须包含next参数,而路由处理函数中只包含 req 和 res 4. next()函数作用
next函数是实现多个中间件连续调用的关键,他表示把流转关系转交给下一个中间件或路由

  1. 创建最简单的中间件
const express = require("express");
const app = express;

// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
  console.log("这是最简单的中间件");
  next();
};

app.listen(80, () => {
  console.log("http://127.0.0.1");
});
  1. 中间件的作用
    多个中间件之间,共享同一份 req 和 res,基于这样的特性,
    我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件进行使用。
const express = require("express");
const app = express();

// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
  const time = Date.now();
  // 为req挂载自定义属性,从而把time共享给后面的路由
  req.startTime = time;
  next();
};

// 将mw注册为全局生效的中间件
app.use(mw);

app.get("/", (req, res) => {
  res.send("Home page." + req.startTime);
});

app.get("/user", (req, res) => {
  res.send("User page." + req.startTime);
});

app.listen(80, () => {
  console.log("http://127.0.0.1");
});

全局生效的中间件

  1. 全局中间件
  • 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件
  • 通过调用app.use(中间件函数)即可定义一个全局生效的中间件
// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
  console.log("这是最简单的中间件");
  next();
};

// 将mw注册为全局生效的中间件
app.use(mw);

例子:

const express = require("express");
const app = express();

// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
  console.log("这是最简单的中间件");
  next();
};

// 将mw注册为全局生效的中间件
app.use(mw);

app.get("/", (req, res) => {
  console.log("调用了'/'这个路由");
  res.send("Home page.");
});

app.get("/user", (req, res) => {
  console.log("调用了'/user'这个路由");
  res.send("User page.");
});

app.listen(80, () => {
  console.log("http://127.0.0.1");
});

  1. 多个全局中间件
    多次调用app.use()。客户端请求到达服务器之后,会按照中间件的先后顺序一次执行调用
    例子:
const express = require("express");
const app = express();

app.use(function (req, res, next) {
  console.log("中间件1");
  next();
});
app.use(function (req, res, next) {
  console.log("中间件2");
  next();
});

app.get("/", (req, res) => {
  res.send("Home page.");
});

app.get("/user", (req, res) => {
  res.send("User page.");
});

app.listen(80, () => {
  console.log("http://127.0.0.1");
});

局部生效的中间件

  • 不使用app,use定义的中间叫做局部生效的中间件,示例:
const express = require("express");
const app = express();

//定义中间件1
const mw1 = function (req, res, next) {
  console.log("这是中间件函数1");
  next();
};


// mw1在“/”局部生效
app.get("/", mw1, (req, res) => {
  res.send("Home page");
});

// mw1对“/user”无影响
app.get("/user", (req, res) => {
  console.log("mw1未生效");
  res.send("User page");
});

app.listen(80, () => {
  console.log("http://127.0.0.1");
});

  • 使用多个局部生效的中间件
    示例:
const express = require("express");
const app = express();

//定义中间件1
const mw1 = function (req, res, next) {
  console.log("这是中间件函数1");
  next();
};

// 定义中间件2
const mw2 = function (req, res, next) {
  console.log("这是中间件函数2");
  next();
};

// 使用多个局部中间件,方式一
app.get("/my1", mw1, mw2, (req, res) => {
  res.send("My1 page");
});

// 使用多个局部中间件,方式二
app.get("/my2", [mw1, mw2], (req, res) => {
  res.send("My2 page");
});

app.listen(80, () => {
  console.log("http://127.0.0.1");
});


中间件的使用注意事项

  1. 一定要在路由之前注册中间件
  2. 客户端发送过来的请求,可以连续调用多个中间件进行处理
  3. 执行完中间件的业务代码之后,不要忘记调用next()函数
  4. 为了防止代码逻辑混乱,调用 next()函数之后不要在后面再写代码
  5. 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象

中间件的分类

① 应用级别的中间件
② 路由级别的中间件
③ 错误级别的中间件
④ Express 内置的中间件
⑤ 第三方的中间件

应用级别的中间件

通过app.use()app.get()app.post(),绑定到 app 实例上的中间件,叫做应用级别的中间件。
示例:

//1.
app.use(function (req, res, next) {
  console.log("中间件1");
  next();
});

//2.
const mw1 = function (req, res, next) {
  console.log("这是中间件函数1");
  next();
};
app.get("/", mw1, (req, res) => {
  res.send("Home page");
});
路由级别的中间件

绑定到express.Router()实例上的中间件,叫做路由级别的中间件。
用法和应用级别的中间件没有区别。
但,应用级别中间件绑定到 app 实例上,路由级别中间件绑定到 router 实例上。
示例:

const app = express()
const router = express.Router()
// 路由级别中间件
router.use(function(req,res,next){
  console.log("Time:",Date.now());
  next();
})

app.use('/',router)
错误级别的中间件
  • 错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
  • 格式:function 处理函数中,必须有 4 个形参,顺序为(err,req,res,next)

示例:

app.get("/", (req, res) => {
  throw new Error("服务器内部发生了错误!");
  res.send("Home page");
});

app.use(function (err, req, res, next) {
  console.log("发生了错误:" + err.message);
  res.send("Error!" + err.message);
});

注意:错误级别的中间件必须注册在所有路由之后!

Express 内置的中间件
  1. express.static:快速托管静态资源的内置中间件,例如:HTML 文件、图片、CSS 样式等
  2. express.json:解析 JSON 格式的请求体数据(4.16+)
  3. express.urlencoded:解析 URL-encoded 格式的请求体数据(4.16+)
    示例:
//配置解析application/json格式数据的内置中间件
app.use(express.json())
//配置解析application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({extended:false}))

示例:

const express = require("express");
const app = express();

// 设置解析表单JSON数据的中间件
app.use(express.json());

// 设置解析application/x-www-form-urlencoded 格式的中间件
app.use(express.urlencoded({ extended: false }));

app.post("/user", (req, res) => {
  // 在服务器使用 req.body 接收客户端发送过来的请求体
  // 默认情况下,若不配置解析表单数据的中间件,req.body 默认等于undefined
  console.log(req.body);
  res.send("ok");
});

app.post("/book", (req, res) => {
  // 在服务器使用 req.body 接收客户端发送过来的请求体
  console.log(req.body);
  res.send("ok");
});

app.listen(80, () => {
  console.log("Express server running at http://172.0.0.1");
});

第三方的中间件

由第三方开发出来的中间件,按需下载并配置第三方中间件,从而提高开发效率

  1. npm install 中间件名
  2. 使用require导入中间件
  3. 调用app.use注册并使用中间件

自定义中间件

例子:模拟一个类似与express.urlencoded这样的中间件,来解析 POST 提交到服务器的表单数据。

① 定义中间件
② 监听 req 的 data 事件
③ 监听 req 的 end 事件
④ 使用 qurestring 模块解析请求体数据
⑤ 将解析出来的数据对象挂载为 req.body
⑥ 将自定义中间件封装为模块
注意:

  1. 当数据量较大时,客户端会把数据切割后,分批发送到服务器,data 事件可能会触发多次,每触发一次 data 事件时,获取到的数据只是完整数据的一部分,需要手动对接收到的数据进行拼接
  2. Node.js内置了一个qureystring模块,专门用来处理查询字符串。通过这个模块提供的 parse()函数,把查询字符串解析成对象格式

代码:

  • 自定义中间件模块:my-body-parser.js
// 引入qureysrting模块
const qs = require("qs");

const bodyParser = (req, res, next) => {
  // 定义str,存储客户端发送过来的数据
  let str = "";
  // 监听req的data事件
  req.on("data", (chunk) => {
    str += chunk;
  });
  // 监听req的end事件
  req.on("end", () => {
    // 这时在str为完整数据
    console.log(str);
    // TODO:把字符串格式的请求体数据,解析成对象格式
    const body = qs.parse(str);
    console.log(body);
    // 挂载为req.body
    req.body = body;
    next();
  });
};
module.exports = bodyParser;
  • 使用自定义中间件
const express = require("express");
const app = express();

// 导入自己封装的my-body-parser
const myBodyParser = require("./10my-body-parser");

app.use(myBodyParser);

app.post("/user", (req, res) => {
  res.send(req.body);
});

app.listen(80, () => {
  console.log("Express server running at http://172.0.0.1");
});

(四)、使用 Express 编写接口

① 创建 express 服务器
② 创建 API 路由模块(在此编写接口)

编写 GET 接口

router.get("/get", (req, res) => {
  // 通过 req.body 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query;
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, //0成功,1失败
    msg: "GET请求成功", //状态描述
    data: query, //需要响应给客户端的数据
  });
});

编写 POST 接口

注意:一般都要配置解析表单数据的中间件

router.post("/post", (req, res) => {
  const body = req.body;
  res.send({
    status: 0,
    msg: "POST请求成功",
    data: body,
  });
});

CORS 跨域资源共享

  1. 接口的跨域问题解决
  • CORS跨域资源共享
  • JSONP:只支持GET
  1. 使用cors中间件解决跨域
    cors 是 Express 的一个第三方中间件。
    步骤:
  • npm install cors
  • 导入const cors = require('cors')
  • 在路由之前调用app.use(cors())配置中间件
  1. CORS 定义
    CORS:跨域资源共享,由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否组织前端 JS 代码与跨获取资源
    浏览器的同源安全策略默认阻止网页跨域获取资源,造成跨域问题。
  2. CORS 注意事项
  • CORS 主要在服务器端进行配置,客户端浏览器无须做任何额外的配置,即可开启了 CORS 接口
  • CORS 在浏览器有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服务器端接口(如:IE10+、Chrome4+、FireFox3.5+)
  1. CORS 响应头
  • Access-Control-Allow-Origin
    语法:Access-Control-Allow-Origin:
    origin 参数指定了允许访问资源的 url
  • Access-Control-Allow-Headers
    语法:res.setHeader('Access-Control-Allow-Headers',参数)
    • 默认情况下,CORS 只支持客户端发送如下 9 个请求头:
      Accept、Accept-Language、Content-Language、DRP、Downlink、Save-Data、Viewport-Width、Width、Content-Type(值仅限于 text/plain、multipart/form-data、application/x-www-form-urluncoded 三者之一)
    • 如果客户端向服务器发送了额外的请求头信息,则需在服务器通过Access-Control-Allow-Headers对额外的请求头进行声明,否则这次请求会失败
  • Access-Control-Allow-Methods
    默认情况下,CORS 仅支持客户端发起GETPOSTHEAD请求。
  1. CORS 请求的分类
    客户端在请求 CORS 接口时,根据请求方式和请求投的不同,可以将 CORS 的请求分为两大类:
    ① 简单请求
    ② 预检请求
  2. 简单请求
    满足条件:
    ① 请求方式:GET、POST、HEAD 三者之一
    ② HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DRP、Downlink、Save-Data、Viewport-Width、Width、Content-Type(值仅限于 text/plain、multipart/form-data、application/x-www-form-urluncoded 三者之一)
  3. 预检请求
  • 定义:在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获取服务器是否允许该实际请求,所以这一次的 OPTION 请求成为“预检请求”。服务器响应预检请求后,才会发送真正的请求,并且携带真实数据。
  • 满足条件:
    ① 请求方式为 GET、POST、HEAD 之外的 Method 类型
    ② 请求头中包含自定义头部字段
    ③ 向服务器发送了 application/json 格式的数据
  1. 简单请求与预检请求的区别
    简单请求的特点:客户端与服务器只会发生一次请求
    预检请求的特点:客户端与服务器会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求。

JSONP 接口

  1. 概念:
    浏览器通过

你可能感兴趣的:(笔记,学习,前端,node.js)