**Node.js **
1.npm的使用
1.1终端中的快捷键
1.使用 ↑键,可以复制上一次输入的代码
2.使用tab可以在当前文件夹选择文件进行切换操作
3.使用esc按键,可以一键清空当前已输入的命令
4.输入cls命令,可以清空终端
5.使用node文件时:node 文件名。进行调用
2.文件系统模块
2.1 什么是fs文件系统模块
fs模块是node.js官方提供、用于操作文件的模块。它提供了一系列方法和属性,用来满足用户对文件操作的需求:
例如:
fs.readFile()方法,用来读取指定文件中的内容。
fs.writeFile()方法,用来向指定的文件中写入内容。
2.2读写指定文件中的内容
1. fs.readFile() 的语法格式
fs.readFile()方法,用来读取指定文件中的内容。
语法:
fs.readFile(path,[options],callback(err,success))
=>参数:
参数1 path:必选参数,字符串,表示文件路径。
参数2 options:可选参数,表示以什么编码格式去读取
参数3 callback:必选参数,文件读取完成后,通过回调拿到读取的结果。
=>callback():
err读取成功时返回null
err读取失败时返回一个错误对象
success 读取成功时返回读取的值
success 读取失败时返回null
2. fs.writeFile() 的示例代码
fs.writeFile()方法,向指定文件路径中,写入文件内容。
语法:
fs.writeFile(path,data[,options],callback(err))
=>参数:
参数1 path:必选参数,需要指定一个文件路径的字符串,表示文件存放路径。
参数2 data :必选参数,表示要写入的内容。
参数3 options:可选参数,表示以什么格式写入文件内容,默认值utf-8
参数4 callback:必选参数,文件读取完成后,通过回调拿到读取的结果。
=>callback():
err写入成功时返回null
err写入失败时返回一个错误对象
2.3路径模块
1.路径拼接带来的问题
在使用fs模块操作文件时,如果提供的操作路径时./或者../开头的绝对路径时,很容易出现动态拼接错误的问题。
原因:代码在运行的时候,会以执行node命令所处的目录,动态拼接出被操作文件的完整路径。
解决方案:在使用fs模块操作文本时,直接提供完整的路径,不要提供./或者../开头的相对路径,从而防止动态路径拼接的问题。
2.解决方式__dirname
__dirname表示当前文件所处的目录,也就可以解决相对路径,容易拼接错误。而完整路径不容易书写问题
2.4 path路径模块
1.path.join(参数1,参数....)代码示例
使用 path.join()方法可以将多个路径片段拼接成完整的路径字符串。
const pathjoin = path.join('参数1',“参数2”,.....)
+注意:凡是涉及到路径拼接的操作,都要使用path.join()方法进 行处理。不要直接用+进行字符串的拼接
2. path.basename()方法,获取路径文件名
=>作用:将路径字符串中,最后的文件名解析出来。
path.basenmae(path[,ext])
=> 参数用法:
path 必选参数,表示一个路径的字符串
ext 可选参数,表示文件扩展名
=>返回值:
路径中的最后一部分的文件名。
- path.extname()方法,获取路径文件名的扩展名
=>作用:获取路径文件名的扩展名。
path.extname(path[,ext])
=> 参数用法:
path 必选参数,表示一个路径的字符串
ext 可选参数,表示文件扩展名
=>返回值:
路径中的最后一部分的文件名的扩展名。
3.http模块
3.1 服务器相关概念
ip地址就是互联网上每台计算机的唯一地址,因此ip地址具有唯一性。如果把“个人电脑”比作“一台电话”,ip地址就是电话号码
=>地址的格式:通常用"电分十进制"表示成(a,b,c,d)的形式,其中,a、b、c、d 都是 0~255 之间的十进制整数。例如:用点分十进制表示的ip地址(192.168.1.1)
+注意:
=> 1 .互联网的每台web服务器,都有自己的id地址,例如:大家可以在 Windows 的终端中运行 ping www.baidu.com 命令,即可查看到百度服务器的 ip 地址。
=>2 . 开发期间,自己的电脑既是一台服务器,也是一个客户端,为了方便测试,可以在自己的浏览器中输入 127.0.0.1 这个ip地址,就能把自己的电脑当做一台服务器进行访问。
3.2 服务器相关的概念
1.域名和域名服务器
=>域名与域名服务器对应的是,人与身份证的关系。ip地址是一长串数字,不直观、不便于记忆。
=>ip地址和域名是一一对应的关系,这份对应关系存放在一种叫域名服务器(DNS)的电脑中。使用者只需要通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供 ip 地址和域名之间的转换服务的服务器。
+注意:
=>单纯使用ip地址,互联网中的电脑也能够正常工作。但是有了域名的加持,能让互联网的事件变得更加方便。
=>在开发测试期间,127.0.0.1 对应的域名是localhost,他们都代表我们自己的这台电脑,在使用效果上没有任何区别。
2.端口号
计算机的端口号,类似于现实生活的门牌号一样。通过门牌号,外卖小哥可以在整栋大楼众多的房间中,将外卖送到你的手中。
同样的道理,在一台电脑中,可以运行成百上千的web服务器。每个web服务器都对应一个唯一的端口号。客户端发送过来的网络请求,通过端口号。可以被准确的交给对应的web服务器进行处理。
+注意:
=>每个端口号不能同时被多个web服务器占用。
=>在实际应用中,url中的 80 端口可以被省略
3.3 创建 web 服务器
1.获得http对象
const http = require('http');
2.通过http对象创建 server 对象,web服务器实例
const server = http**.**createServer();
3.使用服务器实例的 .on() 方法,为服务器绑定一个request事件
每当服务器被请求时,触发.on()方法
server**.**on('request',function(req,res){})
=>request : 绑定request事件
=>req请求对象:存放着与客户端相关的数据或属性
+req对象的方法:
=>req.url : 返回客户请求的url地址
=>req.method:返回客户请求的method类型
=>res 响应对象方法:
=>res.end()方法,向客户端响应内容。并关闭客户端。
4.使用服务器实例的 .listen() 方法,启动服务器
server.liseten(参数1,function(){})
参数1 :启动的服务器端口,如:8080
3.4 根据不同的 url 响应不同的 html 内容
1.核心实现步骤
1)获取请求的 url 地址
2)设置默认的响应内容为 404 Not found
3)判断用户请求是否为 / 或 /index.html 首页
4)判断用户请求是否为 /about.html 关于页面
5)设置 Content-Type 响应头,防止中文乱码
6)使用 res.end() 把内容响应给客户端
4.Node.js 中的模块化
4.1 Node.js 中模块的分类
node.js 中根据模块来源的不同,将模块分为了3大类,分别是:
=>内置模块(内置模块是由 Node.js 官方提供的,例如 fs、path、http等),
=> 自定义模块 (用户创建的每个 .js 文件 ,都是自定义模块)
=> 第三方模块 (由第三方开发出来的模块 , 并非官方提供的内置模块,也不是用户创建的自定义模块,使用需要下载)
4.2 加载模块
使用强大的 require() 方法,可以加载需要的内置模块 、用户自定义模块、第三方模块进行使用。
+注意 : 使用 require() 方法加载其它模块时 ,会执行被加载模块中的代码。
4.3 node.js 中的模块作用域
模块的好处:防止了全局变量污染的问题
4.4 向外共享模块作用域中的成员
=> module.exports 对象
在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供其它使用。
外界用 require() 方法导入自定义模块时 , 得到的就是module.exports 所指的对象
+注意:使用require() 方法导入模块时 , 导入的结果, 永远以 module.exports 指向的对象为准。
=> exports 对象
由于 module.exports 拼写比较复杂。node 提供了 exports 对象。默认情况下, exports 和module.exports 指向同一个对象。最终共享的结果,还是以 module.exports 指向的对象为准
4.5 Node.js 中的模块化规范
node.js 遵循了 CommonJS 模块化规范, CommonJS 规定了“模块的特性” 和 “各模块之间如何相互依赖”
CommonJS 规定:
=> 每个模块内部、”module 变量“代表当前模块
=> module 变量是一个对象,它的 exports 属性 (即 module.exports)是对外的接口。
=> 加载某个模块,其实是加载模块的 module.exports 属性。"require() 方法用于加载模块"
5. npm 与包
5.2 npm 初体验
如果想在项目中安装指定的包,需要运行如下命令:
npm install 包的完整名字
简写
npm i 包的完整名字
5.3 包管理配置文件
1.如何记录项目中安装了哪些包
在项目根目录中,创建一个叫做 package.json 的配置文件, 即用来记录项目中安装了哪些包。从而方便剔除 node_modules 目录之后,在团队成员之间共享项目的源代码。
+注意:今后在项目开发中,一定要把node_modules 文件夹,添加到 .gitgnore忽略文件中
2.快速创建 package.json
npm 包管理工具提供了一个快捷命令,可以在“执行命令是所处的目录中”,快速创建 package.json 这个包管理配置文件:
=>代码:
npm init -y
+注意:
=>上述命令只能在“英文的目录下运行”!! 所以,项目文件夹的名称一定要使用英文命名,“不要使用中文,不能出现空格”
=>运行 npm install 命令安装包的时候,npm 包管理工具会自动把"包的名称"和"版本号",记录到 package.json 中。
3. dependencies(依靠) 节点
package.json 文件中,有一个dependencies (依靠)节点,专门用来记录使用的 npm install 命令安装了哪些包。
4. 一次性安装所有的包
当我们拿到一个剔除了 node_modules 的项目之后,需要先把所有的包下载到项目中,才能将项目运行起来。否则会报类似于下面的错误:
Error:Cannot find module 'moment'
5. 一次性卸载所有包
代码:
=> npm uninstall jquery
卸载指定的包,将 jquery 包卸载,被卸载的包,自动从 package.json 的 dependencies 中移除掉
6.devDependencies 节点
如果某些包“只在项目开发阶段”会用到,在“项目上线之后不会用到”,则建议把这些包记录到 devDependencies 节点中。
代码:
=> npm i 包名 -D
=> npm install 包名 --save-dev
5.4 解决下包速度慢的问题
1.下载慢的原因
npm是国外的服务器,使用下载时间比较漫长
2.切换 npm 的下包镜像源
下包的镜像源,指的是下包的服务器地址。
# 查看当前的下包镜像源
npm config get registry
#将下包的镜像源切换为淘宝镜像源
npm config set registry = registry.npm.taobao.org/
3. nrm
为了方便切换下包的镜像源,我们可以安装 nrm 这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源。
# 通过 npm 包管理器,将 nrm 安装为全局可用的工具
npm i nrm -g
# 查看所有可用的镜像源
nrm 1s
将下的镜像源切换为 taobao 镜像
nrm use taobao
5.5 包的分类
1.项目包
那些被安装到项目的 node_nodules 目录中的包,都是项目包
项目包又分为两类,分别是:
=>开发依赖包(被记录到 devDependencies 节点中的包,只会在开发期间会用到)
=> 核心依赖包 (被记录到 dependencies 节点中的包,在开发和上线期间都会用到)
语法:
=>开发依赖包
npm i 包名 -D
=>核心依赖包
npm i 包名
2.全局包
在执行 npm install 命令是,如果提供了 -g 参数,则会把包安装到全局
3. i5ting_toc
i5ting_toc 是一个可以把 md 文档转换成 html 页面的小工具,使用步骤如下:
#将 i5ting_toc 安装为全局包
npm install -g i5ting_toc
# 调用 i5ting_toc,轻松实现 md 转 html 的功能
i5ting_toc -f 要装换的 md 文件路径 -o
4. 规范的包结构
一个规范的包,他的组成结构,必须符合以下 3 点要求:
=> 包必须以(单独的目录)存在
=> 包的顶级目录下要必须包含 package.json 这个包管理配置文件
=> package.json 中必须包含 name,version,main 这三个属性 , 分别代表:包的名字、版本号、包的入口。
5.6 包管理配置文件
1.包的结构功能
{
"name": 包的名字
"version":包的版本号
"main":包的入口
"description":包的简介
"keyWord":[ "包的关键词1","包的关键词2",包的关键词3,...]
"license": 包遵守的协定 (ISC)
}
5.7 开发属于自己的包
1. 将文本转义为 html
转义方式:
使用 replace (/<|>|"|&/g,(e)=>{
switch(e){
case '<' : retun <,
}
})
5.8 发布包
1.登入npm账号
npm 账号注册完成后,可以在终端中执行 npm login 命令,依次输入用户、密码、邮箱后。即可登录成功
+注意:
在运行 npm login 命令之前,必须先把(下包的服务器)地址切换为 (npm的官方服务器)。否则会发布失败
2.把包发布到 npm 上
将终端切换到包的根目录上,运行 npm publish 命令,即可将包发布到 npm 上 (注意:包名不能雷同)
3.删除以发布的包
运行 npm unpublish 包名 --force 命令, 即可从 npm 删除已发布的包。
+注意:
=> npm unpublish 命令只能删除72小时以内发布的包。
=> npm unpublish 删除的包72小时以内不能发布。
6.模块化的加载机制
6.1 优先从缓存中加载
(模块在第一次加载后会被缓存)。这也以为着多次调用 require() 不会被导致模块的代码被执行多次。
+ 注意:无论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
6.2 内置模块的加载机制
内置模块是由 Node.js 官方提供的模块,“内置模块的加载优先级最高”。
例如, require("fs") 始终返回内置的 fs 模块,及时在 node_modules 目录下有名字相同的包也叫做fs
同时,在使用require()导入自定义模块式,如果省略了文件的扩展名,则 Node.js 会 (按顺序)分别尝试加载以下文件:
1.按照确切的文件名进行加载
2.补全 .js 扩展名进行加载
3.补全 .json 扩展名进行加载
4.补全 .node 扩展名进行加载
5.加载失败,终端报错
6.3 第三方模块的加载机制
如果传递给 require() 的模块标识符不是一个内置模块,也没有以 "./" 或 '../'开头,则 Node.js 会从当前模块的父级目录开始,尝试/node_modules 文件夹中加载第三方模块
如果没有找到对应的第三方模块,则移动到再上一层父级目录中,进行加载,知道文件系统的跟目录
例如:假设在 'c\user\a\b\c\test.js' 文件里调用了 require(‘tl’),则 Node.js 会按以下顺序查找;
=> 'c\user\a\b\c\node_modules\tl
=> 'c\user\a\b\node_modules\tl
=> 'c\user\a\node_modules\tl
...
=> 'c\node_modules\tl
=> 报错 err
6.4 目录作为模块
当把目录作为模板标识符,传递给 require() 进行加载时,会有三种加载方式:
=> 1 . 在被加载的目录下查找一个叫做 package.json 的文件,并寻找 main 属性 ,作为 require()的入口
=> 2 . 如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则Node.js 将会试图加载目录下的 index.js 文件 。
=> 3. 如果以上两步都失败了, 则 Node.js 会在 终端打印错误消息,报告模块的缺失 :error:Cannot find module 'xxx'
7. Express
7.1 express 简介
1. 什么是Express
官方给出的概念: express 是基于 Node.js 品台, 快速,开放,极简的 Web开发框架。
通俗的理解: Express 的作用和 Node.js 内置的 http 模块类似 , 是专门用来创建 Web 服务器的。
Express 的本质:就是一个 npm 上的第三方包,提供了快速创建 Web 服务器的便捷方法。
Express与http的关系,类似 jquery 和 js的关系。前者是后者的封装代码
2. Express 能做什么
对于前端程序员来书,最常见的两种服务器,分别是:
web 网站服务器:专门对外提供 web 网页资源的服务器
api 接口服务器:专门对外提供api 接口的服务器
使用 express,我们可以更方便,快速的创建 web网站服务器 或者 api接口 的服务器
7.2express 基本使用
1.创建 express 服务器
语法:
// 1.导入express
const express = require('express')
// 2.创建 web 服务器
const web = express()
// 3. 调用 app.listen (端口号, 启动成功后的回调函数),启动服务器
web**.listen(80,()=>**{
console**.**log('你的服务器地址为 http://127.0.0.1');
})
2. 监听 GET 请求
通过 web .get() 方法,可以监听客户端的 GET 请求,具体的语法格式如下:
=>语法:
web .get("请求url" ,function(req,res){
处理函数
})
=> 参数1:请求的 url 地址
=>参数2 callback:
req : 请求对象 ( 包含了请求相关的属性与方法)
res : 响应对象 ( 包含了响应相关的属性与方法)
2. 监听 POST 请求
通过 web .post() 方法,可以监听客户端的 GET 请求,具体的语法格式如下:
=>语法:
web .post("请求url" ,function(req,res){
处理函数
})
=> 参数1:请求的 url 地址
=>参数2 callback:
req : 请求对象 ( 包含了请求相关的属性与方法)
res : 响应对象 ( 包含了响应相关的属性与方法)
3. 获取 url 中携带的查询参数 req.query
通过 req.query 对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数:
=> 语法:
req.query : 默认情况下返回一个空对象
客户端使用 ?name = zs&age=20 这种查询字符串形式,发送到服务器的参数,可以通过 req.query 对象访问到,例如:
req.query.name req.query.age
=>代码 :
web.get('/',(req,res)=>{
// req.query 默认是一个空对象
log(req.query)
})
4. 获取 url 中的动态参数 req.params
通过 req.params 对象,可以访问到 url 中,通过:匹配到的动态参数;
语法:
=> url 地址中,可以通过 :参数名 的形式,匹配动态参数值
web.get('/user/:id',(req,res) => {
log(req.params)
//返回值一个对象 id:浏览器输入的值
})
7.3 托管静态资源
1.express.static()
express 提供了一个非常好的函数,叫做 express.static().通过它我们可以<非常方便地创建一个静态资源服务器>。例如:通过以下代码将 public 目录下的图片、css文件 、js文件对外开放访问。
web.use(express.static('public'))
可以访问 public 目录中的所有文件。
+注意:Express 在指定的静态目录中查找文件,并对外提供资源的访问路径。因此,存放静态文件的目录名不会出现在 URL 中。
2.托管多个静态资源目录
如果要托管多个静态资源目录,请多次调用 express.static() 函数;
web.use(express.static('public'))
web.use(express.static('files'))
访问静态文件,express.static() 函数会根据目录的添加顺序查找所需的文件
访问机制:
=>谁写到前面,那就访问前面的页面。后面的不再访问
=>当前面的无法访问时,这时会继续访问后面的页面
3.挂载路径前缀
如果希望在托管的“静态资源访问路径”之前,挂载路径前缀,则可以使用如下方式:
web.use(参数1,express.static('public'))
作用:访问文件路径时,要输入 参数1/ index.js 才能访问 public文件夹内的 index.js 文件
7.4 nodemon
1.安装nodemon
使用全局命令 npm i nodemon -g
2.使用 nodemon
当基于 Node.js 编写了一个网站应用的时候,传统的方式,是运行 node app.js 命令,来启动项目。这样的坏处是代码被修改之后,需要手动重启项目。
现在,我们可以将· node 命令替换成 nodemon 命令,使用 nodemon app.js 来启动项目。这样做的好处是:代码被修改之后,会被 nodemon 监听到,从而实现自动重启项目的效果
8 Express路由
8.1 路由的概念
1.Express 中的路由
在 Express 中,路由指的是 (客户端的请求)与 (服务器处理函数)之间的 映射关系。
Express 中的路由分 3 部分组成,分别是<请求的类型,请求的URL地址、处理函数>格式如下:
web."请求的类型GET\POST"(地址,处理函数)
web.get("./index",function(req,res){
})
2. 模块化路由 router
为了方便对路由进行模块化管理,Express 不建议将路由挂载到 app上 ,而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下:
1)创建路由模块对应的.js文件
2)调用 express.Router() 函数创建路由对象
3)向路由对象上挂载具体的路由
语法:
=>1. 创建方式:
const router =express.router()
=>2. 调用,给路由对象挂载get、post路由
router.get('url',(req,res)=>{
})
=>3.将路由导出,直接将路由对象整个导出
module.exports = router
=>4.外部调用该路由
const getRouter = require('路由的地址')
=>5.注册该路由
web.use(getRouter )
3. 为路由模块添加前缀
为了方便用户访问,可以给路由添加前缀以作为区别:
语法:
web.use('添加的前缀', 路由对象)
9.Express 中间件
9.1.中间件的作用
多个中间件之间,共享同一份 req 和 res,基于这样的特性,我们可以在上游的中间件中,统一为 req 和 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
客户端 (请求)=>中间件1=>中间件2=>中间件n =>(响应)客户端
语法:
web.use( (req,res,next)=>{
next()
} )
next :流转关系 ,转交给下一个中间件或路由。(必须调用)
9.2.定义多个全局中间件
可以使用 web.use() 连续定义多个全局中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。
web.use( (req,res,next)=>{
log 中间件1
next()
} )
web.use( (req,res,next)=>{
log 中间件2
next()
} )
打印 中间件1、中间件2
9.3. 局部生效的中间件
不使用 app.user() 定义的中间件,叫做局部生效的中间件,示例代码如下:
创建一个中间件函数
const middle = (req,res,next) =>{
console**.**log("局部中间件被调用");
next()
}
当路由1 添加中间件函数,路由2不添加时。路由2不会使用
=>路由1,添加了中间件函数
web**.get('/',middle,(req,res)=>**{
res**.**send('我是作用于index的局部中间1')
}
)
=>路由2
web**.get('/user',middle,(req,res)=>**{
res**.**send('我是作用于index的局部中间2')
}
)
9.4.路由可以挂载多个中间件函数
当路由挂载了多个中间件的时候,会按照中间件的顺序依次调用
语法1:多个对象=>
web**.get('/',middle1,middle2,(req,res)=>**{
res**.**send('我是作用于index的局部中间1')
}
)
语法2:数组对象方法=>
web**.get('/',[middle1,middle2],(req,res)=>**{
res**.**send('我是作用于index的局部中间1')
}
)
9.5.中间件的注意事项
=> 一定要在路由之前注册中间件
=> 客户端发过来的请求,可以连续调用多个中间件进行处理
=> 执行完中间件的业务代码之后,不要忘记调用 next() 函数
=> 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
=> 连续调用多个中间件时,多个中间件之间,共享 req,res 对象
9.6.错误级别中间件
错误级别中间件作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃问题。
格式:错误级别中间件的 function 处理函数中,必须有 4 形参,形参顺序从前到后,分别是(err,res,req,next)
web.use(function(err,res,req,next){
err.message
})
+注意:错误类型中间件,必须注册在所有路由之后
9.7 Express 内置的中间件
自 Express 4.16.0 版本开始,express内置了3个常用中间件,极大提高了 Express 项目开发顺序和体验:
=> express.static 快速托管静态资源的内置中间件,例如:html文件、图片、css样式等
=> express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0 + 版本中可用)
+注意:
服务器需要用 req.body 接收数据。
默认情况下,如果不配置解析表单的中间件,则 req.body 的值为 undefined
9.8 自定义中间件
1. 监听请求对象 req 的 data 事件
在中间件中,需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据。
如果数据量比较大,无法一次发送完毕,则客户端把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
const str = ""
req.on('data',(chunk)=>{
str += chunk
})
2.监听请求对象 req 的 end事件
当请求体数据接收完毕之后,会自动触发 req 的 end 事件
因此,我们可以在 req 的 end 事件中,拿到并处理完整的请求体数据。实例代码如下:
req.on('end',()=>{
将请求体数据解析成字符串格式
log(str)
})
3. 使用 querystring 模块解析请求体数据
Node.js 内置了一个 querystring 模块,专门用来处理查询字符串。通过这个模块提供的 parse() 函数, 可以轻松的查询字符串,解析成对象的格式。
使用方式:
1.导入处理 querystring 的 Node.js 内置模块
const qs = require('querystring')
2.调用 qs.parse() 方法,把查询字符串解析为对象
const body = qs.parse(str)
3.上游的中间件 和 下游的中间件 之间,共享一份 req 和 res ,因此可以将解析出的自定义属性挂载到 req 中,命名 req.body。以供下游使用
req.body = body
最后调用 next() 函数,执行后续的业务逻辑。
next()
10. 使用 Express 写接口
1.接口的跨域问题
单个组件编写的 GET 和 POST 接口,存在一个很严重的问题:不支持跨域请求。
解决接口跨域问题的方案主要有两种;
1、CORS (主流的解决方案、推荐使用)
2、JSONP (有缺陷的解决方案,只支持 GET 请求)
2. 使用 cors 中间件解决跨域问题
cors 是 Express 的一个第三方中间件,通过安装和配置 cors 中间件,可以最方便地解决跨域问题。
使用步骤:
=>1. 运行 npm install cors 安装中间件
=>2. 使用 const cors = require("cors") 导入中间件
=>3. 在路由之前调用 web.use(cors()) 配置中间件。
3. cors 响应头部 - Access-Control-Allow-Origin
通过设置 res.setHeader("Access-Control-Allow-Origin",请求地址)。可以对请求的地址做指定,允许访问该资源的外域 URL。
如果指定了 Access-Control-Allow-Origin 字段的值为通配符 "*",表示允许来自任何域的请求。
res.setHeader("Access-Control-Allow-Origin ","*")
如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access - Control - Allow - Headers 对额外的请求头进行声明,否则这次请求会失败!
res.setHeader("Access-Control-Allow-Origin ",“GET”,"POST")
4.简单请求和预检请求的区别
简单请求的特点:客户端与服务器之间只会发送一次请求
预检请求的特点: 客户端与服务器之间会发生两次请求。option 预检请求成功之后,才会发起真正的请求。
预检请求
只要符合以下任何一个条件的请求,都需要进行预检请求:
=> 请求方式为 GET、POST 、HEAD 之外的请求 Method 类型
=> 请求头中包含自定义头部字段
=> 向服务器发送了 application/json 格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送 option 请求进行预检,已获知服务器是否允许该实际请求。所以这一次的 option 请求为“预检请求”,服务器成功响应预检请求后,才会发送真正的请求,并携带真实数据。
11. Mysql 的基本使用
11.1. 增删改查
1.查询语句 Select
查询列 select (查询键名称) from (查询表)
输出值: 键对应的值
2.添加语句 insert into
向某个表添加,插入数据: a 为 a1, b 为 b1
insert into (a,b) valuse (a1,b1)
3. 更改语句 update
对某个字段的值做修改。可以不写where,对该键的所有值做修改
update 数据表名 set 更改的键 = 你修改的值 where 更改的条件 id = 1
对多个字段的值做修改
update 数据表名 set 更改的键 = 你修改的值,更改的键2 = 你修改的值2 where 更改的条件 id = 1
4. 删除语句 Delete
语法: Delete from 表名 where 删除条件
对users 表进行操作,删除 id 为 4 的用户
delete from users where id = 4
11.2 where 子句中运算符的使用
下面的运算符可在 where 字句中使用,用来限定选择的标准
操作符
= 等于
<> 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
between 在某个区间
like 搜索某种样式
注意:在某些版本 SQL 中,操作符 <> 可以写为 !=
11.3 SQL 的 AND 和 OR 运算符
语法:
AND 和 OR 可在 WHERE 子语句中把两个或者多个条件结合起来。
AND: 表示必须同时满足多个条件,相当于 javascript 中2的 && 运算符,例如 if (a>0 && a==101)
UPDATE 表名 set 对内容修改 WHERE 条件1 or 条件2
满足条件1或者2,对内容进行修改
UPDATE student set NAME = '法外狂徒' WHERE gender = '男' or id = 3
以上代码将所有 gender = “男” 或者 id = 3 的对象选取出来
11.4 SQL 的 ORDER BY 子句
对数据进行升降序排序
语法:
select * from 表名 where 键名 (asc、desc) 升序、降序
对数据进行升降序多次排序
语法
select * from 表名 where 健名 (asc、desc) 升序、降序,健名 (asc、desc) 升序、降序
逗号隔开,多次排序
11.5 SQL 的 count(*) 函数
统计所有的列数可以使用 conut(*) 函数
语法:
select count(*) from 列表名 where 条件
select count(*) from student where name = "张三"
使用 AS 为列设置别名
如果希望给查询出来的列名称设置别名,可以使用 AS 关键字
select count(*) AS total from student where name = "张三"
返回值:
total : 3
12.在项目中操作 MySQL
1.配置 mysql 模板
// 1.导入 mysql 模块
const mysql = require('mysql')
// 2. 建立与数据库 Mysql 的链接关系
const db = mysql**.**createPool({
host:'127.0.0.1', //数据库的ip地址
user:'root', //登录数据库账号
password:'admin', //登录数据库的密码
database:'demo' //指定要操作哪个数据库
})
测试 mysql 模块能否正常工作
调用 db.query() 函数,指定要执行的 SQL 语句,通过回调函数拿到执行的结果。
db.query((" SQL 语句 "),(err,success)=>{
if(err) return err.message
log success
})
2.标记删除
使用 delete 语句,会真正的把数据从表中删除掉。为了保险起见,推荐使用标记删除的形式,来模拟删除的动作。所谓的标记删除,就是在表中设置类似于 status 这样的状态字段,来标记当前这条数据是否被删除。
当用户执行了删除的动作时,我们并没有执行 DELETE 语句把数据删除掉,而是执行了 UPDATE 语句,将这条数据对应的 status 字段标记删除即可:
status = 0 默认为0表示存在 status = 1 默认删除
db.query('update 表名 set status = 1 where id=?')