携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
一、初识NodeJs
1.定义:
Node.js是一个基于Chrome V8 引擎的 JavaSript 的运行环境
2.nodejs和JavaScript有什么区别?
nodejs是⼀个JavaScript运⾏环境(平台),JavaScript是编程语⾔。
3.nodejs中能否运⾏alert⽅法?
nodejs中⽆法运⾏alert⽅法,DOM和BOM这类⽅法也⽆法在node中运⾏。
4.上手Node—Node环境执行js代码
- 在vs code里面创建一个test文件
// test.js
console.log('hello,我是node')
- 运行命令
node test.js
- 安装nodemon工具实现热更新
命令:npm i nodemon -g
执行:nodemon test.js
5.深⼊理解commonjs模块规范
1)commonjs规范
commonjs 是一种使用广泛的 JavaScript 模块化规范,核心思想是通过 require 方法来同步地加载依赖的其他模块,通过 module.exports 导出需要暴露的接口。
每⼀个⽂件相当于⼀个模块,有⾃⼰的作⽤域,其模块⾥的变量、函数以及类都是私有的,对外不可⻅的。
2)module.exports模块导出
//创建calculate.js文件
function add(a, b) {
console.log(a + b);
}
function decrease(a, b) {
console.log(a - b);
}
module.exports = {
add,
decrease,
};
3)require模块引⽤
let cal = require('./calculate')
cal.add(10,5)
cal.decrease(100,50)
4)loadsh
//它是⼀个⼀致性、模块化、⾼性能的 JavaScript 实⽤⼯具库
安装命令:npm i loadsh --save/cnpm i loadsh --save
5)nodejs中的全局对象
//nodejs中的全局对象是global,定义全局变量⽤global对象来
global.a = 2 //定义全局变量,可在其他模块中直接使⽤,相当在js里面是window对象
6)JavaScript中为什么要使用commonjs?
- js没有模块系统,不具备封闭的作用域和依赖管理
- 缺少文件系统的IO流API(例如文件的导入导出)
- 不具备包管理系统
7)commonjs 和 ES6 模块的区别
- commonjs 模块输出的是一个值的拷贝(不会改变值),ES6 模块输出的是值的引用(会改变值)
- commonjs 模块是运行时加载,ES6 模块是编译时输出接口
- commonjs 模块的 require() 是同步加载模块,ES6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段
二、Node基础—核心模块
1.核心模块之Buffer和Stream模块
1)Buffer定义
Buffer 是内存区域,固定大小的内存块(无法调整大小),可以将 buffer 视为数组,每个元素代表一个数据字节,由Node中Buffer类实现
2)Buffer的数据形式
保存在Buffer中的数据是以十六进制的形式展示的,更加简短,但是计算机底层处理的还是二进制数据
3)为什么需要Buffer?
-
帮助开发者处理二进制数据,传统上数组只处理字符串而不是二进制数据、 图片、音视频
-
当对文件的IO操作时,输出的速度大于输入的速度,则会将数据存入Buffer中
4)创建buffer
- Buffer.alloc(size[, fill[, encoding]])://创建一个指定大小的buffer,无法调整大小
console.log(Buffer.alloc(10));//创建⼀个⻓度为10的Buffer,默认填充0
- Buffer.allocUnsafe(size)://在buffer池中使用原有的buffer,可能含有敏感数据,但是性能会更好
console.log(Buffer.allocUnsafe(10));//创建⼀个⻓度为10未初始化的buffer
- Buffer.from(array)://创建buffer,填充整数数组
console.log(Buffer.from([1,2,3]));//创建buffer,填充[1,2,3]
- Buffer.from(string[, encoding])//创建buffer,填充字符串
console.log(Buffer.from('miaozai')); //创建buffer,填充字符串
5)常用的属性和方法
- Buffer.byteLength: 返回字符串的字节⻓度
console.log(Buffer.byteLength('中⽂'));//6,⼀个⽂字代表3个字节
- Buffer.isBuffffer(obj): 判断是否是buffer
console.log(Buffer.isBuffer({}));
- Buffer.concat(list[, totalLength]): 合并buffer
const buf = Buffer.from('hello');
const buf2 = Buffer.from('miaozai');
console.log(buf);
console.log(buf2);
console.log(Buffer.concat([buf,buf2]));
console.log(Buffer.concat([buf,buf2],10));
- buffer.write(string[, offset[, length]][, encoding]) 将字符写⼊buffer,返回已经写⼊的字节数
const buf = Buffer.allocUnsafe(20);
console.log(buf);
// console.log(buf.write('buffer'));
console.log(buf.write('buffer',5,3));
console.log(buf);
- buffer.fill(value[, offset[, end]][, encoding]) 填充buffer
console.log(buf.fill('miao',5,10));
- buf.toString([encoding[, start[, end]]]) 将buffer解码成字符串形式
const buf = Buffer.from('test');
console.log(buf.toString('utf8',1,3));
- buf.toJSON 返回 buffer 的 JSON 格式
const buf = Buffer.from('test');
console.log(buf.toJSON());
- buf.equals(otherBuffer) 对⽐其它buffer是否具有完全相同的字节
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex');
const buf3 = Buffer.from('ABCD');
console.log(buf1);
console.log(buf2);
console.log(buf1.equals(buf2));
// 打印: true
console.log(buf1.equals(buf3));
- buf.slice([start[, end]]) 切割buffer
const buf = Buffer.from('abcdefghi');
console.log(buf.slice(2,7).toString());//cdefg
- buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]]) 拷⻉buffer
const buf = Buffer.from('abcdefghi');
const buf2 = Buffer.from('test');
// console.log(buf.slice(2,7).toString());
// console.log(buf.copy(buf2));
// console.log(buf2.toString());
console.log(buf2.copy(buf,2,1,3));
console.log(buf.toString());
4)Node.js 中有四种基本的流类型
Writable - 可写⼊数据的流(例如fs.createWriteStream() )。
Readable - 可读取数据的流(例如fs.createReadStream() )。
Duplex - 可读⼜可写的流(例如 net.Socket )。
Transform - 在读写过程中可以修改或转换数据的 Duplex流(例如zlib.createDeflate())。
- 创建读取⽂件流fs.createReadStream(path[, options])
- 创建写⼊⽂件流fs.createWriteStream(path[, options])
- 管道流readable.pipe(destination[, options])
let rs = fs.createReadStream('./a.js');
let ws = fs.createWriteStream('./b.txt');
rs.pipe(ws)
2.核心模块之文件系统fs模块使用
1)什么 fs 模块
node提供用来操作文件的内置模块,模块里有很多的属性和方法,用于处理文件,如:文本,图片,视频,音频等等
引⼊⽂件系统模块fs
2)引⼊⽂件系统模块fs
const fs = require('fs')
3)⼀些⽂件的常⽤api操作
记得先创建hello.txt文件
- fs.readFile(path[, options], callback) //读取⽂件
// path:文件路径
// options:编码格式
// callback:回调函数
//err
//data 读取的数据
fs.readFile('./hello.txt','utf8',(err,data) => {
if(err) throw err;
console.log(data);
})
- fs.writeFile(fifile, data[, options], callback) 写⼊⽂件
//file ⽂件名或⽂件描述符。
//data 写⼊的数据
//options
//encoding | 写⼊字符串的编码格式 默认值: 'utf8' 。
//mode ⽂件模式(权限) 默认值: 0o666 。
//flag 参阅⽀持的⽂件系统标志。默认值: 'w' 。
//callback 回调函数
//err
fs.writeFile('./hello.txt','this is a test!',err => {
if(err) throw err;
console.log('写⼊成功');
})
- fs.appendFile(path, data[, options], callback) 追加数据到⽂件
//path ⽂件名或⽂件描述符。
//data 追加的数据
//options
//encoding 写⼊字符串的编码格式 默认值: 'utf8' 。
//mode ⽂件模式(权限) 默认值: 0o666 。
//flag 参阅⽀持的⽂件系统标志。默认值: 'a' 。
//callback 回调函数
//err
const buf = Buffer.from('hello world!')
fs.appendFile('./hello.txt',buf,(err) => {
if(err) throw err;
console.log('追加成功');
})
- fs.stat(path[, options], callback) 获取⽂件信息,判断⽂件状态(是⽂件还是⽂件夹)
//path
//options
//bigint 返回的 fs.Stats 对象中的数值是否应为 bigint型。默认值: false 。
//callback
//err
//stats <fs.Stats> ⽂件信息
fs.stat('./hello.txt',(err,stats) => {
if(err){
console.log('⽂件不存在');
return;
}
console.log(stats);
console.log(stats.isFile());
console.log(stats.isDirectory());
})
- fs.rename(oldPath, newPath, callback) 重命名⽂件
//oldPath 旧⽂件路径名字
//newPath 新⽂件路径名字
//callback 回调函数
//err
fs.rename('./hello.txt','./test.txt',err => {
if(err) throw err;
console.log('重命名成功');
})
- fs.unlink(path, callback) 删除⽂件
//path 文件路径
//callback
//err
fs.unlink('./test.txt',err => {
if(err) throw err;
console.log('删除成功');
})
4)使⽤⽂件系统操作⽂件夹
- 引入模块
const fs =require('fs');
- fs.mkdir(path[, options], callback) 创建⽂件夹
//path
//options
//recursive 是否递归创建 默认值: false 。
//mode ⽂件模式(权限)Windows 上不⽀持。默认值: 0o777 。
//callback
//err
//创建a文件夹
fs.mkdir('./a',err => {
if(err) throw err;
console.log('创建⽂件夹成功');
})
//递归创建文件夹
fs.mkdir('./b/c',{
recursive:true
},err => {
if(err) throw err;
console.log('创建⽂件夹成功');
})
- fs.readdir (path[, options], callback) 读取⽂件夹
// path
//options
//encoding 默认值: 'utf8' 。
//withFileTypes 默认值: false 。
//callback
//err
//files <string[]> | <buffer[]> | <fs.Dirent[]>
fs.readdir('./',{
encoding:'buffer', //设置buffer,files返回⽂件名为buffer对象
withFileTypes:true //带上⽂件类型
},(err,files) => {
if(err) throw err;
console.log(files)
})
- fs.rmdir(path[, options], callback) 删除⽂件夹
//path
//options
//maxRetries 重试次数。出现这类错误 EBUSY 、 EMFILE 、 ENFILE 、 ENOTEMPTY 或者EPERM ,每⼀个重试会根据设置的重试间隔重试操作。如果 recursive 不为true则忽略. 默认值: 0。
//retryDelay 重试的间隔,如果 recursive 不为true则忽略. 默认值: 100 。
//recursive 如果为 true ,则执⾏递归的⽬录删除。在递归模式中,如果 path 不存在则不报告错误,并且在失败时重试操作。默认值: false 。
//callback
//err
fs.rmdir('./b',{
recursive:true
},err => {
if(err) throw err;
console.log('删除⽂件夹成功');
})
- 监听⽂件变化 chokidar
安装chokidar:npm install chokidar --save-dev
Chokidar.watch(path,[options])
chokidar.watch('./',{
ignored:'./node_modules'
}).on('all',(event,path) => {
console.log(event,path)
})
3.核心模块之路径模块path使用
- path.basename(path[,ext]) 返回path的最后⼀部分
- path.dirname(path) 返回path的⽬录名
- path.extname(path) 返回path的扩展名
- path.join([...paths]) 路径拼接
- path.normalize(path) 规范化路径
- path.resolve([...paths]) 将路径解析为绝对路径
- path.format(pathObject) 从对象中返回路径字符串
- path.parse(path) 返回⼀个对象,包含path的属性
- path.sep 返回系统特定的路径⽚段分隔符
- path.win32 可以实现访问windows的path⽅法
- __filename 表示当前正在执⾏的脚本的⽂件名
- __dirname 表示当前执⾏脚本所在的⽬录
三、http全⾯解析
1.什么是http协议
即超⽂本传送协议,是Web联⽹的基础,也是移动或PC联⽹常⽤的协议之⼀,HTTP协议是建⽴在TCP协议之上的⼀种应⽤
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器响应请求,从建⽴连接到关闭连接的过程称为“⼀次连接”
HTTP请求-HTTP响应
2.http 消息结构(报文)
- 请求报文
请求行:请求方法 URL地址 协议名
请求头:报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的基本信息
请求体:请求的参数,可以是json对象,也可以是前端表单生成的key=value&key=value的字符串
- 响应报文
响应行:报文协议及版本 状态码
响应头:报文头包含若干个属性,格式为“属性名:属性值”
响应正文:响应报文体,我们需要的内容,多种形式比如html、json、图片、视频文件等
- 请求方法
GET: 向服务器获取资源,比如常见的查询请求
POST: 向服务器提交数据而发送的请求
Head: 和get类似,返回的响应中没有具体的内容,用于获取报头
- 状态码
1XX
100 收到请求,需要请求者继续执行操作,比较少用101 切换请求的协议
2XX:
请求成功,常用的 200
3XX: 重定向,浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取;
好处:网站改版、域名迁移等,多个域名指向同个主站导流
必须记住:
301:永久性跳转,比如域名过期,换个域名
302:临时性跳转
304:数据已经在客户端缓存,不需要请求更多的数据
4XX: 客服端出错,请求包含语法错误或者无法完成请求
必须记住:
400: 请求出错,比如语法协议
403: 没权限访问
404: 找不到这个路径对应的接口或者文件
405: 不允许此方法进行提交,Method not allowed,比如接口一定要POST方式,而你是用了GET
5XX: 服务端出错,服务器在处理请求的过程中发生了错误
必须记住:
500: 服务器内部报错了,完成不了这次请求
503: 服务器宕机
3.剖析Node中http模块相关知识点
-
http模块
是Node.js 网络的关键模块,用来创建web服务器,通过 http.createServer() 就能将普通的电脑变成本地的web服务器 -
ip
在互联网中每个服务器都有一个唯一的ip地址,本地服务器ip地址为:127.0.0.1在开发环境下,自己的电脑既是客户端也是服务器,浏览器输入http://127.0.0.1:3000就能访问 -
域名
由于ip地址不直观,不方便记忆,诞生了域名地址来替换ip地址访问iP地址和域名是一对多的关系,对应关系在域名服务器中(DNS)保存 -
端口
端口就像是银行的办事窗口,每个窗口可以提供不同的服务,银行就是服务器
4.创建一个本地的web服务器
//引入http模块
const http = require('http');
//创建服务器
const server = http.createServer();
//监听客户端的请求
server.on('request', (req, res) => {
const mess = `请求地址:${req.url},请求方法:${req.method}`;
//解决中文乱码的问题
res.setHeader('Content-Type', 'text/html;charset=utf-8');
//响应的内容和结束本次请求
res.end(mess);
});
//启动服务器
server.listen(3000, () => {
console.log('服务运行在:http://127.0.0.1:3000');
});
四、NodeJS连接Mysql
1.安装mysql模块
npm install mysql --save
2.连接数据库
const mysql = require('mysql')
//创建连接
const conn = mysql.createConnection({
host:'localhost',
user:'root',
password:'123456789',
port:'3306',
database:'数据库自定义名字'
})
//建⽴连接
conn.connect()
let sql = 'select * from user where id = ?'
//执⾏sql语句
conn.query(sql,[4],(err,result)=>{
if(err) throw err
console.log(result)
})
//关闭连接
conn.end()
3.mysql连接池
const mysql = require('mysql')
//创建连接池
const pool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: 'root',
password: '123456789',
port: '3306',
database: '数据库自定义名字'
})
//获取连接
pool.getConnection((err, conn) => {
if (err) throw err
let sql = 'select * from user where city = ?'
//执⾏sql语句
conn.query(sql, ['⼴州'], (err, result) => {
conn.release()
if (err) throw err
console.log(result)
})
})
五、express框架知识
1.什么是深入理解express框架
-
定义
基于 Node.js 平台,快速、开放、极简的 Web 开发框架
其实就是node npm包管理工具中的第三方包,可以使用express快捷创建服务器 -
express框架特性
- 可以设置中间件来响应 HTTP 请求。
- 提供⽅便的路由定义⽅式
- 可以通过模板引擎动态渲染 HTML ⻚⾯
- 简化获取http请求参数的⽅式
-
其他的node框架
1)koa2
2)egg
3)nest.js -
安装
npm install express --save
- 创建服务器
const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('service run in http://127.0.0.1:3000');
});
2.监听数据请求和参数处理
- get
// url:请求地址
// req:包含请求的属性和方法
// res:包含响应的属性和方法
const express =require('express')
const app= express()
app.get('/userInfo', (req, res) => {
// 响应数据处理
cosole.log(req.query)
//向客户端响应数据
res.send('请求成功')
});
- post
// url:请求地址
// req:包含请求的属性和方法
// res:包含响应的属性和方法
const express =require('express')
const app= express()
app.post('/login', (req, res) => {
// 响应数据处理
cosole.log(req.body)
//向客户端响应数据
res.send('请求成功')
});
3.express框架—路由配置模块化
-
express中的路由
1)前端中的路由 router 一样,在不同的路由页面展示不同的内容
2)express中的路由就是不同路径的接口,响应客户端不同的数据 -
创建路由模块
// router/user.js
const express = require('express');
const router = express.Router();
// 登录
router.post('/user/login', (req, res) => {
res.send('登录');
});
// 获取用户数据
router.get('/user/userInfo', (req, res) => {
res.send('获取用户数据');
});
module.exports = router;
4.express中间件
- 什么是中间件
中间件是Express 框架中的⼀个重要概念。中间件(Middleware)是⼀个函数,它可以访问请求对象 req , 响应对象 res , 和 web 应⽤中处于请求-响应循环流程中的中间件,⼀般被命名为next 的变量。 - 使用中间件注册路由模块
//app.use 加载⽤于处理http请求的middleware(中间件),当⼀个请求来的时候,会依次被这些
middlewares处理。
const router = require('./router/user');
//使用中间件注册路由模块
app.use(router);