Node_学习笔记
不同技术点 : 24px 红色 加粗 标题一
技术点子模块 : 18px 黑色加粗 标题二 缩进
子模块在细分 : 16px
普通文字 : 14px
NodeJS入门
- NodeJS是什么 : Node.js 就是一款应用程序,是一款软件,它可以运行 JavaScript
CDM常用命令 : 切换盘符 : C: D: 切换工作目录 : cd(change dir) 查看目录文件 : dir
Buffer
let buf = Buffer.alloc(10); //清零创建
console.log(buf)
let buf_2 = Buffer.allocUnsafe(10000); //不清零创建
console.log(buf_2)
let buf_3 = Buffer.from('hello');
console.log(buf_3);
FS模块
文件增删查改API
fs.writeFile() //异步
fs.writeFileSync() //同步
fs.appendwriteFile() //追加文件写入
fs.createWriteStream() //流式写入 .write('value')
fs.readFile() //文件读取
fs.readFileSync() 同步读取
fs.createReadStream() //流式文件读取
fs.rename() //重命名 移动
fs.unlink() fs.rm()//删除
fs.mkdir() //创建文件夹
fs.readdir //读取文件夹
fs.stat //查看文件信息
路径补充说明
相对路径不靠谱 , 运行的时候是根据命令行所在的目录运行的脚本。
__irname : 保存的是所在文件的所在目录的绝对路径
PATH模块
path.resolve(__dirname, 'index.html') //拼接绝对路径
HTTP协议
请求头 :
IP的分类
http服务器注意事项 :
- 当服务启动后 , 更新代码要重启。
- 响应内容中文乱码解决办法 :
response.setHeader('conteng-type','text/html;charset=utf-8')
- HTTP端口80 , HTTPS端口443
http模块_获取请求路径与查询字符串
new URL('url','IP')
url.searchParams.get('value')
http模块_静态资源和动态资源
静态资源是指内容长时间不发生改变的资源 , 列如图片、视频、CSS文件、JS文件、HTML文件 。
动态资源是指内容经常更新的资源 , 列如百度首页、网易首页、京东搜索页面等。
http模块_页面URL的使用场景
- a标签 href
- link 标签 href
- script 标签 src
- img标签 src
- video audio 标签 src
- form 中的 action
- AJAX 请求中的 URL
GET和POST应用场景与区别
GET 请求的情况
- 在地址栏直接输入 url 访问
- 点击 a 链接
- link 标签引入 css
- script标签引入js
- video 与audio 引入多媒体
- img 标签引入图片
- form 标签中的 method 为 get (不区分大小写)
- ajax中的get请求
POST 请求的情况
- form 标签中的 method 为 post (不区分大小写)
- AJAX的 post 请求I
区别
- 作用。GET 主要用来获取数据,POST 主要用来提交数据
- 参数位置。GET 带参数请求是将参数缀到 URL之后,POST带参数请求是将参数放到请求体中
- 安全性。POST 请求 相对 GET 安全一些,因为在浏览器中参数会暴露在地址栏
- GET 请求大小有限制,一般为 2 K,而 POST 请求则没有大小限制
模块化
模块暴露数据的方式两种 :
1.module.exports = vlaue
2.exports.name = value
注意 : module.exports暴露任何数据 exports = module.exports = {}
require
在模块中使用require 传入文件路径即可引入文件
const test = require( ./me .js );
require 使用的一些注意事项
- 对于自己创建的模块,导入时路径建议写 相对路径 ,且不能省略 ./ 和 ../
- js 和 json 文件导入时可以不用写后缀,c/c++编写的 node 扩展文件也可以不写后缀,但是一般用不到
- 如果导入其他类型的文件,会以 js 文件进行处理
- 如果导入的路径是个文件夹,则会首先 检测该文件夹下 package.json 文件中 main 属性对应的文件,
- 如果存在则导入,反之如果文件不存在会报错。
- 如果 main 属性不存在,或者 package,json 不存在,则会尝试导入文件夹下的 index.js 和 index.ison.如果还是没找到,就会报错
导入 node.js 内置模块时,直接 require 模块的名字即可,无需加./和../
require 导入 自定义模块 的基本流程
- 将相对路径转为绝对路径,定位目标文件
- 缓存检测
- 读取目标文件代码
- 包裹为一个函数并执行 (自执行函数)。通过 arguments.callee.toString() 查看自执行函数
- 缓存模块的值
- 返回 module.exports 的值
CommonJS模块化规范
module.exports 、exports 以及 require 这些都是 CommonJS 模块化规范中的内容而 Node,js 是实现了 CommonJS 模块化规范,二者关系有点像 JavaScript 与 ECMAScript
包管理工具
require导入npm包基本流程
1.在当前文件夹下node_modules中寻找同名的文件夹 , package.json => main : 'name' , name指定文件
2.在上级目录中下的 node_modules 中寻找同名的文件夹,直至找到磁盘根目录
开发依赖与生产依赖
类型 | 命令 | 补充 |
生产依赖 |
npm i -S uniq npm i --save uniq |
-S 等效于 --save, -S 是默认选项 包信息保存在 package.json 中 dependencies 属性 |
开发依赖 | npm i -D less npm i --save-dev less |
-D 等效于 --save-dev |
Express
express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
app.(path,callback)
获取请求参数
express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//获取请求的路由规则
app.get('/request', (req, res) => {
//1. 获取报文的方式与原生 HTTP 获取方式是兼容的
console.log(req.method);
console.log(req.url);
console.log(req.httpVersion);
console.log(req.headers);
//2. express 独有的获取报文的方式
//获取查询字符串
console.log(req.query); // 『相对重要』
// 获取指定的请求头
console.log(req.get('host'));
res.send('请求报文的获取');
});
//启动服务
app.listen(3000, () => {
console.log('启动成功....')
})
获取路由参数
app.get('/:id.html', (req, res) => {
res.send('商品详情, 商品 id 为' + req.params.id);
});
express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式
//获取请求的路由规则
app.get("/response", (req, res) => {
//1. express 中设置响应的方式兼容 HTTP 模块的方式
res.statusCode = 404;
res.statusMessage = 'xxx';
res.setHeader('abc','xyz');
res.write('响应体');
res.end('xxx');
//2. express 的响应方法
res.status(500); //设置响应状态码
res.set('xxx','yyy');//设置响应头
res.send('中文响应不乱码');//设置响应体
//连贯操作
res.status(404).set('xxx','yyy').send('你好朋友')
//3. 其他响应
res.redirect('http://atguigu.com')//重定向
res.download('./package.json');//下载响应
res.json();//响应 JSON
res.sendFile(__dirname + '/home.html') //响应文件内容
});
express 中间件
let recordMiddleware = function(request,response,next){
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
定义路由中间件
app.get('/路径',`中间件函数`,(request,response)=>{
});
app.get('/路径',`中间件函数1`,`中间件函数2`,(request,response)=>{
});
静态资源中间件
const app = express();
//静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录
app.use(express.static('./public')); //当然这个目录中都是一些静态资源
获取请求体数据 body-parser
const bodyParser = require('body-parser');
//获取中间件函数
//处理 querystring 格式的请求体
let urlParser = bodyParser.urlencoded({extended:false}));
//处理 JSON 格式的请求体
let jsonParser = bodyParser.json();
//设置路由中间件,然后使用 request.body 来获取请求体数据
app.post('/login', urlParser, (request,response)=>{
//获取请求体数据
//console.log(request.body);
response.send('获取请求体数据');
});
//获取到的请求体数据:
[Object: null prototype] { username: 'admin', userpass: '123456' }
EJS 模板引擎
模板引擎是分离 用户界面和业务数据 的一种技术 : https://ejs.bootcss.com/
//1.引入ejs
const ejs = require('ejs');
//2.定义数据
let person = ['张三','李四','王二麻子'];
//3.ejs解析模板返回结构
//<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构
let html = ejs.render(‘<%= person.join(",") %>’, {person:person});
//4.输出结果
console.log(html);
语法
执行JS代码 : <% code %>
输出转义的数据到模板上 : <%= code %>
输出非转义的数据到模板上 : <%- code %>
Mongodb
使用
//1. 安装 mongoose
//2. 导入 mongoose
const mongoose = require('mongoose');
//3. 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/bilibili');
//4. 设置连接回调
//连接成功
mongoose.connection.on('open', () => {
console.log('连接成功');
//5. 创建文档结构对象
let BookSchema = new mongoose.Schema({
title: String,
author: String,
price: Number
});
//6. 创建文档模型对象
let BookModel = mongoose.model('book', BookSchema);
//7. 插入文档
BookModel.create({
title: '西游记',
author: '吴承恩',
price: 19.9
}, (err, data) => {
if (err) throw err
//输出 data 对象
console.log(data);
//8. 断开连接
mongoose.disconnect();
});
});
//连接出错
mongoose.connection.on('error', () => {
console.log('连接出错~~');
})
//连接关闭
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
字段类型
类型 | 描述 |
String | 字符串 |
Number | 数字 |
Boolean | 布尔值 |
Array | 数组,也可以使用 [] 来标识 |
Date | 日期 |
Buffer | Buffer 对象 |
Mixed | 任意类型,需要使用 mongoose.Schema.Types.Mixed 指定 |
ObjectId | 对象 ID,需要使用 mongoose.Schema.Types.ObjectId 指定 |
Decimal128 |
高精度数字,需要使用 mongoose.Schema.Types.Decimal128 指定 |
字段值验证
Mongoose 有一些内建验证器,可以对字段值进行验证
//必填项
title: {
type: String,
required: true // 设置必填项
},
//默认值
author: {
type: String,
default: '匿名' //默认值
},
//枚举值
gender: {
type: String,
enum: ['男','女'] //设置的值必须是数组中的
},
//唯一值
username: {
type: String,
unique: true
},
CURD
//增加
SongModel.create({
title:'给我一首歌的时间',
author: 'Jay'
}, function(err, data){
//错误
console.log(err);
//插入后的数据对象
console.log(data);
});
//删除
SongModel.deleteOne({_id:'5dd65f32be6401035cb5b1ed'}, function(err){
if(err) throw err;
console.log('删除成功');
mongoose.connection.close();
});
//批量删除
SongModel.deleteMany({author:'Jay'}, function(err){
if(err) throw err;
console.log('删除成功');
mongoose.connection.close();
});
//更新一条数据
SongModel.updateOne({author: 'JJ Lin'}, {author: '林俊杰'}, function (err) {
if(err) throw err;
mongoose.connection.close();
});
//批量更新数据
SongModel.updateMany({author: 'Leehom Wang'}, {author: '王力宏'}, function (err) {
if(err) throw err;
mongoose.connection.close();
});
//查询
SongModel.findOne({author: '王力宏'}, function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
//根据 id 查询数据
SongModel.findById('5dd662b5381fc316b44ce167',function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
//批量查询数据
SongModel.find(function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
//加条件查询
SongModel.find({author: '王力宏'}, function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
条件控制
//运算符
//在 mongodb 不能 > < >= <= !== 等运算符,需要使用替代符号
> 使用 $gt
< 使用 $lt
>= 使用 $gte
<= 使用 $lte
!== 使用 $ne
db.students.find({id:{$gt:3}}); id号比3大的所有的记录
逻辑运算
$or 逻辑或的情况
db.students.find({$or:[{age:18},{age:24}]});
$and 逻辑与的情况
db.students.find({$and: [{age: {$lt:20}}, {age: {$gt: 15}}]});
正则匹配
条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询
db.students.find({name:/imissyou/});
个性化读取
//0:不要的字段
//1:要的字段
SongModel.find().select({_id:0,title:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据排序
//sort 排序
//1:升序
//-1:倒序
SongModel.find().sort({hot:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据截取
//skip 跳过 limit 限定
SongModel.find().skip(10).limit(10).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
})
会话控制
HTTP 是一种无状态的协议,它没有办法区分多次的请求是否来自于同一个客户端, 无法区分用户
而产品中又大量存在的这样的需求,所以我们需要通过 会话控制 来解决该问题
常见的会话控制技术有三种:
- cookie
- session
- token
cookie
cookie 是 HTTP 服务器发送到用户浏览器并保存在本地的一小块数据 , 按域名划分
服务器写入cookie , 后续向服务器发送请求时,就会自动携带 cookie
session
3.1 session 是什么
session 是保存在 服务器端的一块儿数据 ,保存当前访问用户的相关信息
3.2 session 的作用
实现会话控制,可以识别用户的身份,快速获取当前用户的相关信息
3.3 session 运行流程
填写账号和密码校验身份,校验通过后创建 session 信息 ,然后将 session_id 的值通过响应头返回
给浏览器
有了 cookie,下次发送请求时会自动携带 cookie,服务器通过 cookie 中的 session_id 的值确定用
户的身份
cookie 和 session 的区别主要有如下几点:
1. 存在的位置
cookie:浏览器端
session:服务端
2. 安全性
cookie 是以明文的方式存放在客户端的,安全性相对较低
session 存放于服务器中,所以安全性 相对 较好
3. 网络传输量
cookie 设置内容过多会增大报文体积, 会影响传输效率
session 数据存储在服务器,只是通过 cookie 传递 id,所以不影响传输效率
4. 存储限制
浏览器限制单个 cookie 保存的数据不能超过 4K ,且单个域名下的存储数量也有限制
session 数据存储在服务器中,所以没有这些限制
token
token 是什么
token 是服务端生成并返回给 HTTP 客户端的一串加密字符串, token 中保存着 用户信息
token 的作用
实现会话控制,可以识别用户的身份,主要用于移动端 APP
token 的工作流程
- 填写账号和密码校验身份,校验通过后响应 token,token 一般是在响应体中返回给客户端的
- 后续发送请求时,需要手动将 token 添加在请求报文中,一般是放在请求头中
JWT
JWT(JSON Web Token )是目前最流行的跨域认证解决方案,可用于基于 token 的身份验证
JWT 使 token 的生成与校验更规范
我们可以使用 jsonwebtoken 包 来操作 token
//导入 jsonwebtokan
const jwt = require('jsonwebtoken');
//创建 token
// jwt.sign(数据, 加密字符串, 配置对象)
let token = jwt.sign({
username: 'zhangsan'
}, 'atguigu', {
expiresIn: 60 //单位是 秒
})
//解析 token
jwt.verify(token, 'atguigu', (err, data) => {
if(err){
console.log('校验失败~~');
return
}
console.log(data);
})
跨站资源用post请求 , get有风险CSRF跨站请求伪造
思维导图 :