更多内容建议官网走一波,这里是部分总结哦~
- node基础
- 文件读取
- path模块
- node的模块化
- 模块作用域
- nodejs遵循的是commonJs规范
- 模块的加载机制
- node web服务器http
- express模块
- 数据库模块
- sql基本用法
- sql进阶内容
- 服务端验证
- sessiong工作原理
- jwt json web token
文件读取
读取路径的问题
当我们使用fs读或取文件的时候,如果不是恰好处于执行的这个文件,那么node会优先从执行node的那个文件开始查找
解决
使用完全路径
缺点:移植性差,不利于维护
__dirname 表示当前目录路径
path模块
如果是../那么会抵消路径,不建议使用+字符来拼接路径地址
方法
path.join(路径,路径) path.basename(路径,后缀[options]) path.extname(路径)
node的模块化
模块化
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干个模块的过程,对于整个系统来说,模块是可以组合、分解和更换的单元
优势:
可复用、可维护、按需加载
模块化规范即对模块拆分和组合时需要遵循的规则,降低沟通成本
分类
内置模块
由node官方提供的,如fs,path
自定义模块
自己写的
第三方模块
非官方,由用户自定义的模块,需要下载使用的
加载方式:
require
模块作用域
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块中访问
防止了全局变量的污染
通过module进行导出,导入使用require,导入导出的是一个对象,因此支持对象的结构;require导入的时候永
远以module.exports为基准
module.exports和exports指向的地址是相同的,但是当一个模块中既有module.exports和exports的时候,
并且都做了修改,
那么此时二者的值不一定相等了
nodejs遵循的是commonJs规范
- 变量方法等职能使用自己模块内的
- 导出使用exports(module.exports)
- 导入使用require,并始终指向module.exports所导出的对象
模块的加载机制
优先从缓存中加载,提高模块的加载效率
内置模块加载机制:内置模块的加载优先级最高
自定义模块加载必须是路径,否则会当成内置模块或者第三方模块
自定义模块加载机制
按文件名加载
补全.js
补全.json
补全.node
第三方模块加载机制
先在项目的node_module中查找
在user路径下找node_module中查找
在根目录为node_module中查找
目录作为模块加载的时候
先在package.json中找main路径
然后在目录下的index.js,如果还没有则报错
其他
npm版本:moment@2.22.0
以点分十进制的形式组成,大版本+功能版本+bug修复版本
npm config get registry
npm config set registry=https: registry.npm.taobao.org
nrm工具
npm i nrm -g
nrm ls
nrm use taobao
node web服务器http
IP地址
ip地址是互联网每台计算机的唯一地址,因此具有唯一性
普通的电脑和服务器相差一个第三方的web服务器,而node可以通过http模块自行搭建web服务器,从而对外提供网
络资源
ip地址采用“点分十进制”,表示(a.b.c.d)每一位位0-255之间的十进制整数
域名和域名服务器
IP和域名是一一对应的关系,这份关系就存在域名服务器中(DNS);但是域名并不能直接就访问,还需要让域名
服务器进行转换,因此域名
服务器就是提供ip地址和域名之间转换的服务器,域名的使用使得互联网的访问变得更加方便
我们的电脑127.0.0.1对应的是localhost
端口号
计算机的端口号类似门牌号,由于实际生活中有N多个服务器,但是我们需要准确识别客户端发过来的网络请求是来自
哪个队赢的web服务器,因
此就需要通过端口号来进行区分
每个端口号不能同时被多个web服务占用
实际应用中只有80端口可以被省略
创建web服务器
req请求对象
当web服务器接收到request的请求时,会触发requests所绑定的事件,通过req可以访问与客户端相关的数据和属性,包括url、method
res响应内容
访问与服务器相关的数据或属性
像客户端响应一些内容,如res.end('jjj')
解决中文乱码
res.setHeader('Content-Type','text/html;charset=utf-8')
express模块
express是基于node.js平台,快速、开放极简的web开发框架,用来创建web服务器的
用途
web网站服务器 api接口服务器
基本使用
req.query 拿到URL的传参数
req.params拿到动态传的参数 app.get('/',(req,res)=> { }
托管静态资源,创建静态资源服务器
express.static(静态文件路径)
app.use(路径前缀(可选),express.static('./clock'))
express在指定的静态目录中查找文件,并对外提供资源的都访问路径,因此,存放静态文件的目录不会出现在url中
nodemon 持久化调试
参考:https://www.jianshu.com/p/a35dfc72c6e6
路由
express中的路由是客户端请求和服务器处理函数之间的映射关系,分别由请求类型+请求URL地址+处理函数组成;每当
一个请求到达服务器
时,会先按照定义的路由先后匹配,只有method和url匹配成功之后才会触发对应的处理函数;同时我们也希望将路由模
块化
中间件
在完成一个请求之前,中间会进行多次的预处理
因此当一个请求到达服务之前,可以连续调用多个中间件,从而对请求进行多次预处理
流程:客户端请求=》中间件1- N=》处理请求=》响应客户端
格式:function(req,res,next){} 包含一个next,可以把一个中间流转交给下一个路由或者中间件
注意:
针对模块化的路由,中间件的全局使用应该在所有注册路由的前面先使用use才能保证给所有的模块化路由正确添加中间件
作用:
多个中间件,共享同一份req和res,因此我们可以在上游统一为reqe/res添加属性或者方法,供下游的中间件或者路由
使用
多个全局中间件定义则是依次执行
全局中间件和模块内的中间件:先执行全局的,然后在执行模块内的中间件;是否执行模块内的中间,按照客户端请求和路
由注册顺序来
如果提前注册的路由为客户端的请求,那么中间件执行到当前模块注册的路由,并执行当前模块内的中间件,后面注册的
路由模块内的中
间件不在执行;执行结果一直按照注册路由的顺序一直执行到最后一个注册的路由
局部中间件
app.use('/api',ww,profileROuter); ww为中间件
分类
应用级中间件,绑定到app.use()
路由级别中间件,绑定到router.use()
错误级别中间件,补货项目中的错误,function(err,req,res,next){}
内置中间件:express.static(),express.json(),express.urlencoded({extended: false})
使用:router.use(express.json()),默认req.body返回是undefined
第三方中间件
npm i xx
aa = equire(xx)
app.use(aa)
数据库模块
cors(跨域资源共享)
是由一系列hhttp响应头组成,这些http响应头决定了浏览器是否阻止前端js代码跨域请求资源
解决跨域
使用中间件cors或者使用jsonp,但是jsonp职能支持get 方法
设置源和headers
Access-Control-Allow-Origins
Access-Control-Allow-Headers
Access-Control-Allow-Methods
响应一个jsonp是响应一个函数const str =${funcName}(${JSON.stringify(data)})
;的过程,其中funcname是来自req.query.callback的值
数据库
数据库是用来组织、存储和管理数据的仓库
数据组织结构
数据库 数据表 数据行 字段,每个字段有对应的数据类型
工具: mysql mysql workbench
什么是sql
结构化查询语言,用来专门访问和处理数据库的编程语言。能够让我们以编程的形式操作数据库的数据;只能在关系型数据库中使用
sql基本用法
select 查询数据表中的内容
select * from 表
select username,password from users
insert into 向数据表中插入新的行
insert into users (passwork,username) values ('1233','tony')
insert into users set ? where id = ?
update 修改数据表中的数据,set的多个数据使用逗号(,)进行分割
update users set password='123' where id = 4
update users set ? where id = ?
delete 删除数据行(一般不用,更建议使用update进行标记删除)
delete from users where id = 4
注意:我下载的工具不能直接使用表,而应该数据库后面跟上表,即my_db_01.users
oerder by
按照所给的列进行排序 desc asc(ascending: [əˈsendɪŋ] ) 分别表示降序和升序
操作数据库:
查看所有数据库
show databases;
查看某个数据库的定义信息
show create database db1;
删除数据库
drop database db1;alter
操作数据表:
创建表,类型有int varchar double(4,1)(表明4位数,小数一位整数两位)
date(1996-07-21) timestap(2022-12-11 10:51:30)
create table if not exists my_db_01.student // if not exists可省略
查询表结构
desc my_db_01.student
修改表名称
alter table my_db_01.student rename to my_db_01.student2
给表增加一列,varchar注意给自负大小,如255
alter table my_db_01.student2 add sports varchar(255)
删除表的某一列
alter table my_db_01.student2 drop age
删除表/数据
drop table if exist my_db_01.student2 全删除
truncate table my_db_01.student2 删除保留表结构
delete from my_db_01.student2 where id = 1 逐行删除,不适用大量数据
修改表结构 change column xx
ALTER TABLEmy_db_01
.cmswing_auth_rule
CHANGE COLUMNpid
pid
INT NOT NULL DEFAULT '0' ;
查看safe-updates的工作状态
show variables like 'sql_safe_updates'
set sql_safe_updates = 0
sql进阶内容
主要介绍: 排序查询、聚合函数、模糊查询、分组查询、分页查询、(内连接、外连接)、子查询
age between 20 and 30 表明[20,30]之间 这个用来替换&&符号,即age>= 20 && age<=30
age in (20,30) 用来替换or 即age = 20 or age = 30
is not null 不为空
example:select * from my_db_01.student2 where sports is not null;
模糊查询like _:单个字符 %:多个任意字符
example: select * from my_db_01.student2 where name like 'w%';
distinct : remove duplicate values 返回不重复的init_name行,可用于计算行数量
example: select distinct init_name from my_db_01.student2;
排序查询 order by (desc asc)
init: zs ls. ww wb wb2
name: ls wb wb2 ww zs
age: null 20 22 30
聚合查询: count max min sum avg 个数 最大最小 求和 平均
count() 查询值的个数
avg 如果列表中有null将不能计算出平均值(保留三位小数),但是能计算出总数
example: select count() from my_db_01.student2;
分组查询: 查询某一类的内容,如某一项,按照某个规则获取的的平均分,规则下分组的个数等;甚至还可以加上where等
进行区间查询
example: select sex,avg(age),count(id) from my_db_01.student2 group by sex;
分页查询
语法:limit 开始的索引,每页查询的条数;
公式:开始的索引 = (当前的页码 - 1) * 每页显示的条数
limit 是一个MySQL"方言"
example: select * from my_db_01.student2 limit 0,3 // 包含条数区间范围是:[0,3)
子查询
查询嵌套中的语句
example: 年龄最大用户的信息。 关键字:年龄最大、用户信息
年龄最大:select max(age) from my_db_01.student2;
用户信息: select * from my_db_01.students where age = xxx
汇总等于: select * from my_db_01.student2 where age = ( select max(age) from my_db_01.student2 );
子查询的结果是单行单列的 他可以作为条件 使用运算符进行运算
子查询的结果是多行单列的 可以使用 in 运算符来判断
select * from my_db_01.student2 where id in ( select id from my_db_01.student2 where name = 'aa' or name = 'bb'); // id=2/3分别表示 aa bb
子查询结果是多行多咧的 可以作为一张虚拟表参与查询
就这两句,没搞明白,怎么t1可以作为变量!!!使用并参与查询
select id,init_name,age,department from my_db_01.student2 t1 where department='master' or department='shooter';
select count(*) from my_db_01.student2 t1 where t1.department = 'master';
练习题
update my_db_01.
ev_article_cate
set name='语文',alias='y11uwen' where id=3;
select * from my_db_01.ev_article_cate
desc my_db_01.ev_users
show create table my_db_01.ev_users
alter table my_db_01.student rename to my_db_01.student2
alter table my_db_01.student2 add nickname varchar(255);
update my_db_01.student2 set nickname ='zs' where name = 'zs';
update my_db_01.student2 set nickname ='ls' where name = 'ls';
update my_db_01.student2 set nickname ='ww' where name = 'ww';
update my_db_01.student2 set nickname ='wb' where name = 'wb';
update my_db_01.student2 set nickname ='wb' where name = 'wb2';
alter table my_db_01.student2 drop age
insert into my_db_01.student2 values (1,'zs',411.2,'1996-07-21','2022-12-11 10:51:30','pingpont');
delete from my_db_01.student2 where id = 1;
set sql_safe_updates = 0;
show variables like 'sql_safe_updates';
insert into my_db_01.student2 (name,init_name) values ('wb2','wb');
update my_db_01.student2 set sex = 'girl' where name = 'zs';
select * from my_db_01.student2 order by age;
select distinct init_name from my_db_01.student2;
select * from my_db_01.student2 where name like 'w%';
select * from my_db_01.student2 where sports is not null;
select * from my_db_01.student2 where age between 22 and 30;
select * from my_db_01.student2;
select avg(age) from my_db_01.student2;
select sex,avg(age),count(id) from my_db_01.student2 group by sex;
select * from my_db_01.student2 limit 0,3;
select max(age) from my_db_01.student2;
select * from my_db_01.student2 where age = ( select max(age) from my_db_01.student2 );
select id,init_name,age,department from my_db_01.student2 t1 where department='master' or department='shooter';
select count(*) from my_db_01.student2 t1 where t1.department = 'master';
select * from my_db_01.student2 where id in ( select id from my_db_01.student2 where department='master' or department='shooter') ;
alter table my_db_01.student2 add department varchar(255) ;
update my_db_01.student2 set department = 'master' where name = 'zs';
update my_db_01.student2 set department = 'shooter' where name = 'ls';
update my_db_01.student2 set department = 'master' where name = 'wb';
update my_db_01.student2 set department = 'shooter' where name = 'wb2';
select * from my_db_01.student2;
服务端验证
服务端渲染推荐使用session认证机制,而前后端分离则是jwt认证机制
session
http的无状态性,指客户端端每次http请求都是独立的,连续多个请求之间没有用直接的关系,服务器不会主动保留每次http的状态
cookie
cookie是存储在用户浏览器中一段不超过4kb的字符串,他有一个名和一个值组成,和其他几个用于控制cookie有效期、安全性和适用范围的可选属性组成;不同域名下的cookie各自独立的,每当客户端发起请求时,会自动把当前域名下所有呀未过期cookie一同发给服务器
特点
自动发送
域名独立
4kb大小限制
过期时限
第三方包:express-session
sessiong工作原理
浏览器初次发起请求,并提交账号和密码;
服务器验证密码,并将登录成功的用户信息存储在服务器的内存中,同时生成对应的cookie字符串,响应给客户端;
客户端自动把cookie存储到当前域名;
当客户端再次发起请求时,会通过请求头自动把当前域名下的所有可用cookie发给服务器;
服务器从请求头中请求携带的cookie,找到内存中存储的用户信息;
当身份验证成功后再响应客户端;
使用过程
const expressSession = require('express-session');
app.use(expressSession({
secret: 'zhu',
resave: false,
saveUninitialized: true, // 保存为初始化
}))
登录
app.post('/api/login',(req,res) => {
if (req.body.username != 'admin'|| req.body.password != '1234') {
return res.send({
status: 1,
msg: 'login fail'
})
}
req.session.user = req.body;
console.log(req.session)
req.session.islogin = true;
res.send({
status: 0,
msg: 'login success'
})
})
销毁:
req.session.destroy(
)
jwt json web token
session需要配合cookie实现,而cookie不支持跨域,所以当前端跨域请求后段接口的时候就不使用了,需要做额外的配置才能实现
跨域认证解决方案
工作原理
首先客户端向服务器发起一次请求,服务器验证成功后生成对应的token字符串,并返还给客户端;
接着客户端将token保存到本地;
当客户再次发起请求的时候,通过请求头的Authorization 将token发给服务器,服务器将token还原成对应的用户信息对象;
最后根据用户信息对象和内存进行比对,比对成功后响应给浏览器
组成
Header Payload Signature(保证安全性)
Authorization: Bearer <token>
express-jwt jsonwebtoken
定义secret
用于保证jwt字符串的安全性,专门用来加密和解密的密钥;因此当生成jwt字符串的时候,使用secret对用户信息进行加密
当需要还原jwt字符串的时候,则对secret进行解密
使用方法:
登录的时候使用jwt生成token:let token = jwt.sign({ username: req.body.username } ,secretStr ,{ expiresIn: '1h'})
注意加密的字段不要说隐私字段,比如密码
接着注册中间件,注意写法,algorithms([ˈælgərɪðmz])说必填字段
引入:var { expressjwt: expressjwt } = require("express-jwt");
注册:
app.use(expressjwt({
secret: secretStr,
algorithms: ["HS256"]
}).unless({ path: [/^/api//]}))
获取token则需要给请求的headers加上Authorization:Bearer <token>
看都看到这里了,不妨点赞支持支持~