Node.js快速入门
一、Node.js
1.前言
本笔记学习视频: https://www.bilibili.com/video/BV1a34y167AZ
Node.js是一个基于Chrome V8引擎的JavaScript运行环境。
Node.js是Javascript的后端运行环境,无法调用DOM和BOM等浏览器内置API。
1 | #执行js文件 |
2.模块
2.1 fs文件系统模块
Node.js提供的用来操作文件的模块。
1 | //导入fs模块 |
fs.readFile(path[,options],callback)
方法,读取指定文件的内容- 参数:文件路径、表示以什么编码格式读取文件、文件读取完成后,通过回调函数拿到读取的结果。
- 回调函数的参数err对象是否为null,是读取成功,否则读取失败
err.message
返回失败信息。
fs.writeFile(file,data[,options],callback)
方法,用来向指定文件写入内容- 参数:指定存放的文件路径、表示写入的内容、表示写入格式、写入完成后的回调函数。
- 写入成功err为null,否则为错误对象。
2.2 path路径模块
1 | //导入path模块 |
path.join([...path])
方法,将多个路径片段拼接成完整的路径- 参数:多个路径字符串
path.basename(path[,ext])
方法,从路径解析文件名- 参数:路径、文件扩展名
2.3 http模块
用来创建web服务器的模块。
创建web服务器步骤:
1 | //1.导入http模块 |
根据url响应不同的html内容:
1 | server.on('request',(req,res)=>{ |
2.4 模块化
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。
优点:
- 提高代码的复用性
- 提高代码的可维护性
- 可以实现按需加载
分类:
- 内置模块:Node.js提供的模块
- 自定义模块:用户自己创建的js文件
- 第三方模块:第三方开发出来的模块,需要先下载
加载模块:
1 | const fs=require('fs') //加载内置模块,直接写名字 |
注意:require()
方法加载模块,就会执行模块
模块作用域:
自定义模块的变量、方法,只能在当前模块内被访问。
每个js模块都有一个module对象,它里面存储了和当前模块有关的信息。
moudle.exports
对象,将模块内的成员共享出去。
1 | //1.挂载属性 |
简化代码使用exports
对象,与moudle.exports
对象用法一样,且两者指向一样。
2.5 包
包是指第三方模块。node_modules
文件夹存放项目安装的包,package-lock.json
存放包的配置文件
1 | #安装全局包 |
npm规定,在项目根目录中,必须提供一个叫做package.json
的包管理配置文件,记录一些项目信息
- 项目的名称、版本号、描述等
- 项目中都用到了哪些包
- 哪些在开发中使用
- 哪些在开发和部署都要使用
1 | #新建项目时,创建package.json文件 |
注意:
- 项目所在的文件夹路径只能为英文
- 运行npm install安装包时,会自动向
package.json
添加信息 - 运行npm uninstall卸载包时,会自动删除
package.json
中包相关信息 - 节点dependencies会记录开发和部署都会用到的包
- 节点devDependencies记录仅开发时用的包
切换国内源下载包
1 | # 查看当前包的下载源 |
模块加载:
- 模块在第一次加载后会被缓存
- 无论什么模块,都会先从缓存加载
- 被加载目录先查找
package.json
的文件,并寻找main
属性,作为require()
加载入口 - 如果没有
package.json
文件,查找该目录下的index.js
文件 - 如果没有找到
index.js
文件,会输出错误信息
3.Express
基于Node.js平台,快速、开发、极简的Web开发框架
3.1 基本使用
1 | //导入express |
监听请求
- GET请求
1 | app.get('/user/:id',function(req,res){ |
- POST请求
1 | app.post('url',function(req,res){ |
1 | //托管静态资源,让文件夹都能让人访问,但存放静态资源的目录名不会出现在url中 |
3.2 路由
Express 中,客户端请求与服务器处理函数之间的映射关系。
Express的路由分为3部分,分别是请求的类型、请求的URL、处理函数
为了方便管理需要对路由进行模块化:
- 创建路由模块的js文件
- 调用
express.Router()
函数创建路由对象 - 向路由对象上挂载路由
- 使用
module.exports
向外共享路由对象 - 使用
app.use()
函数注册路由模块
1 | var express = require('express') |
3.3 中间件
当一个请求到达Express的服务器后,可以连续调用多个中间件,从而对这次请求进行预处理。
中间件函数的形参必须包含next参数。
next()函数把流转关系转到下一个中间件。
1 | //中间件函数 |
调用app.use(中间件函数)
,可以定义一个全局生效的中间件。
多个中间件共享同一个req和res,可以在上游添加自定义的属性或者方法,给下游使用
局部中间件:把中间件对象放在路由的url与处理函数之间,该中间件只对这个路由产生效果。
分类:
- 应用级别的中间件:绑定到app实例上的中间件
- 路由级别的中间件:绑定到router实例上的中间件
- 错误级别的中间件:专门捕获项目的抛出的异常错误(需要放在所有路由之后),必须有四个形参,(err,req,res,next)
- Express内置的中间件
express.static
快速托管静态资源express.json
解析JSON格式的请求体数据express.urlencoded
解析url格式的请求数据
- 第三方的中间件
自定义中间件:
1 | const qs = require('querystring') |
3.4 接口
1 | //创建服务器 |
1 | const express = require('express') |
跨域问题:CORS和JSONP
CORS实现跨域响应步骤:
- 安装cors中间件:
npm i cors
- 使用
const cors=require('cors')
导入中间件,要在路由之前 - 在路由之前调用配置中间件
app.use(cors())
4.数据库
4.1 MySQL使用入门
结构:数据库、数据表、数据行、字段(列)
SQL:结构化查询语言,专门访问和处理关系数据库。
sql的关键字大小写不敏感
1 | --向表中插入数据 |
1 | -- 删除表中某一行数据 |
1 | -- 更新表中某一行某一列数据 |
1 | --从指定的表中查询所有的数据 |
WHERE可以添加运算符来筛选特定字段
=
、<>
、>
、<
、>=
、<=
、BETWEEN
、LIKE
AND
、OR
运算符就是且和或,用来增加筛选条件
1 | --按照列名称大小进行升序排序 |
1 | --统计表中列为某值的个数 |
4.2 项目中连接MySQL数据库
1.安装MySQL数据库第三方模块
mysql
1 | #mysql数据库 |
2.通过mysql模块连接到MySQL数据库
1 | //导入模块 |
3.通过mysql模块执行SQL语句
1 | const sqlStr = 'select * from users' |
4.3 身份验证
服务端渲染:在服务器动态拼接字符串数据,然后发送HTML页面
优点:
- 前端耗时少
- 有利于SEO
缺点: - 占用服务器端资源
- 不利于前后端分离,开发效率低
前后端分离:后端只负责API接口,前端使用Ajax调用接口
优点:
- 开发体验好
- 用户体验好
- 减轻服务器端的渲染压力
缺点: - 不利于SEO
身份认证:
1.服务端渲染:Session认证机制
- HTTP请求的无状态性,每次HTTP请求都是独立的。
- Cookie存储在浏览器中不超过4kb的字符串。不同域名的cookie各自独立,每当客户端发起请求时,会自动把当前域名下的未过期的cookie一同发送给服务器。
- 服务器先通过响应头发送cookie给浏览器,浏览器保存cookie,浏览器再通过请求头发送cookie给服务器,服务器再响应内容。
- cookie不具有安全性
- session验证
1 | //使用session中间件 |
2.前后端分离:JWT认证机制
由于session需要配合cookie才能实现,而cookie默认不支持跨域访问,此时需要额外配置。
JWT是最流行的跨域认证解决方案。
服务器将用户信息加密成Token字符串,发送到客户端,客户端保存后,再发送Token,服务器把Token还原后进行身份验证。
JWT的组成部分:Header(头部)、Payload(有效荷载)、Signature(签名),三者使用英文点号分割
JWT放在HTTP请求头的Authorization字段中
安装JWT包
1 | npm i jsonwebtoken express-jwt |
1 | //导入JWT |
5.在express中使用swagger写API文档
5.1 安装和使用swagger
方法一:使用jsdoc文档注释来生成API文档
1 | # 安装相关工具 |
1 | // app.js |
1 | //在路由模块前写下面的注释 |
方法二:使用json文件来写
1 | # 安装相关工具 |
1 | // app.js |
不熟悉语法时,使用在线的 swagger editor 进行API接口的编辑
选择File->Convert and save as JSON
,下载swagger.json
放进项目中
熟悉语法后,直接对swagger.json
进行修改,不需要编辑器了
官方文档:https://swagger.io/docs/specification/about/
方法三:使用yaml文件来写
其实是利用yamljs模块把yaml文件转化为json文件,如果直接写json文件,会发现json文件的所有属性都会加双引号,还有很多格式类的限制,没有yaml写起来舒服,快速。
而且yaml文件写法才是最贴合官网的语法。
1 | # 安装相关工具 |
1 | // app.js |
5.2 YAML
YAML是一种标记语言,文件名为.yaml
- 大小写敏感
- 使用缩进标识层级关系
- 缩进不允许Tab,只允许空格
- 缩进的空格个数不重要,但是同级元素需要左对齐
- 注释:
#
- 支持的数据类型:
- 对象
- 数组:使用
-
添加在元素前,表示该数组的元素,每一个数组元素都得添加。 - 纯数:任意不可分的数据
|
使用换行>
忽略换行$变量
标记一个属性,用<<: *变量
来导入标记非重复的属性值
5.3 OpenAPI 规范
- 数据类型
type |
format |
评论 |
---|---|---|
integer |
int32 |
有符号 32 位 |
integer |
int64 |
有符号 64 位 (a.k.a long) |
number |
float |
|
number |
double |
|
string |
||
string |
byte |
base64 编码字符 |
string |
binary |
任何八位字节序列 |
boolean |
||
string |
date |
由full-date 定义 RFC3339 |
string |
date-time |
由date-time 定义 RFC3339 |
string |
password |
提示 UI 以隐藏输入 |
URL中的相对引用
除非另有说明,否则所有属于 URL 的属性都可以是 RFC3986 定义的相对引用。使用服务器对象中定义的 URL 作为基本 URI 来解析相对引用。$ref
中使用的相对引用按照 JSON 引用进行处理,使用当前文档的 URL 作为基本 URI。
具体规范见:OpenAPI规范英文版,OpenAPI规范中文版