# node相关
# 1.fs(file system)模块
# 1.1 读
fs.readFile(文件的路径,回调函数)
//回调函数 异步的
err //如果文件的路径不存在 则err就是一个错误对象
data //如果文件的路径存在 则data就是读取出的数据 数据是Buffer格式的
Buffer//格式的数据可以使用toString()转成字符串
const data = fs.readFileSync(文件的路径)
//这个函数是同步的 函数的返回值是读取文件的数据
fs模块读取到的内容是Buffer格式
示例:fs存取一张图片,读取到的内容是buffer
const fs = require('fs')
const path = require('path')
const filePath = path.join(__dirname,'/public/uploads/001.jpg')
const bufferData = fs.readFileSync(filePath);
//得到的是buffer格式字符串
//buffer展示为16进制<Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 00 48...
//bufferData.toString('base64')方法可以将buffer转为字符串 base64位
const base64Data = bufferData.toString('base64')
//再从base64转回buffer,并存图片,看什么效果
const newBufferData = new Buffer(base64Data,'base64')
const newFilePath = path.join(__dirname,'/public/uploads/003.jpg')
fs.writeFileSync(newFilePath,newBufferData);
//这么做是因为目前只知道fs存图片用Buffer
# 1.2 写
异步
fs.writeFile('./1.txt','我是海文',function(err){
console.log(err)
})
参数1:路径,参数二:数据,参数3:回调函数
同步
fs.writeFileSync('路径',数据)
//需要注意,写文件操作时,如果路径存在(即文件存在),是修改文件内容
//如果路径不存在(文件不存在),才是创建文件,写入内容
# 1.3 其余方法
//删除文件
fs.unlinkSync('D:/Windows 7 Documents/Desktop/正则题目答案1.html')
//创建新的空文件夹
fs.mkdirSync('D:/Windows 7 Documents/Desktop/day02')
//删除指定的文件夹
fs.rmdirSync('D:/Windows 7 Documents/Desktop/day02')
//读取指定文件夹的数据
fs.readdir('D:/Windows 7 Documents/Desktop/test',function(err,data){
console.log(err,data)
})
//查看文件/文件夹的状态
console.log(fs.statSync('D:/Windows 7 Documents/Desktop/1.mp4'));
//判断文件是否存在
console.log(fs.existsSync('./buffer1.js'));
//rename(老路径,新路径,回调函数) 把原来的文件从老路径移到新路径 并且修改文件名
fs.rename('D:/Windows 7 Documents/Desktop/1.js','./buffer.js',function (err,data) {
console.log(err, data);
})
/*
* 只要文件的状态改变了就会触发回调函数 nextStat是改变后的文件状态 preStat改变前的文件状态
* watchFile(文件的路径,监听的频率,回调函数)
* */
console.log('执行')
fs.watchFile('./1.txt',{interval:23},function(nextStat,preStat){
console.log(nextStat.size,preStat.size)
})
# 2. path
# 2.1.常用来读取或上传文件时设置路径
console.log(path.join(__dirname,'images'))
//当前所处目录拼接上'/images' /会自动处理
//这个模块专门用来处理路径
const path = require('path')
console.log(__filename)
//序列化路径 返回一个对象
console.log(path.parse(__filename))
//查看文件的后缀名
console.log(path.extname(__filename))
//返回最后一个\后面的数据
console.log(path.basename(__filename))
//返回最后一个\前面的数据
console.log(path.dirname(__filename))
# 2.2 快速创建自定义目录
const fs = require('fs')
const path = require('path')
exports.file = function(data){
let {name,fileData} = data
//如果heaven文件夹已经存在 就不创建了
if(!fs.existsSync(name)){ //如果文件夹不存在 就创建文件夹
fs.mkdirSync(name);
fileData.forEach(item=>{
const {type} = item;
const fullpath = path.join(__dirname,name,item.name)
if(type==='dir'){ //如果type是dir 就创建文件夹
fs.mkdirSync(fullpath)
}else{
fs.writeFileSync(fullpath,'我是html文件')
}
})
}
}
const {file} = require('./file')
let programeData = {
name:'heaven', //heaven文件夹
fileData:[
{
name:'css',
type:'dir'
},
{
name:'js',
type:'dir'
},
{
name:'images',
type:'dir'
},
{
name:'index.html',
type:'file'
}
]
}
file(programeData);
# 2.3 包管理器
# 2.3.1 npm 全称:node package manager(node的包管理器)
node的模块分类 核心模块:fs path http url querystring 自定义模块:自己写的模块 第三方模块:别人写的模块
npm
开发环境:在开发阶段运行的代码 --save-dev -D
生产环境:当代码开发完毕 投放给用户使用时运行的代码 --save -S 默认
-g 全局安装 在任何目录下都可以使用cnpm指令 相当于环境变量
npm init -y 初始化项目文件
npm install 包名 下载包
npm uninstall 包名 删除包
npm install 自动下载package.json文件中的依赖
# 2.4 cmd简单命令
cmd命令 command
window+R 打开命cmd窗口(命令行窗口 黑窗口)
d: 切到d盘目录
cd --> change directory 跳转目录
cd ../ 跳到上一级目录
cd / 跳到根目录
mkdir --> make directory 创建目录
rmdir --> remove directory 删除目录
cd.> 1.txt 创建1.txt文件
del 1.txt 删除1.txt文件
1.txt 打开当前的目录中的1.txt文件
# 2.5 express
# 2.5.1 express模块动态路由
get数据:req.params
post数据 req.body
返回数据给前台 res.send
//引入express包
const express = require('express')
const app = express()
//前台的多个路径都可以匹配到后台的一个路径 动态路由
app.get('/article/:id/:xxx',function(req,res){
// let {id} = req.params
console.log(req.params)
res.send(req.params)
})
//自动为public目录中的文件设置路由
app.use(express.static('public'))
app.listen(3002,()=>{
console.log('3002端口成功运行');
})
# 2.5.2 experss获取post数据
解析post数据需要用到body-parser
//引入express包
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
//使用bodyParser
app.use(bodyParser.urlencoded({extended: false}))
//接受post方式发送的数据
app.post('/heaven', function (req, res) {
console.log('post请求过来了');
console.log(req.body)
// res.end({name:'heaven'})
//send函数是express新增的 这个方法可以发送数组和对象给前台
res.send([1, 2, 3])
})
//自动为public目录中的文件设置路由 静态资源访问
app.use(express.static('public'))
app.listen(3001, () => {
console.log('3001端口成功运行');
})
# 2.5.3 洋葱模型
//引入express包
const express = require('express')
const app = express()
app.get('/',function(req,res,next){
console.log(1)
next() //触发下个一个中间件函数
console.log(2)
})
app.get('/',function(req,res,next){
console.log(3)
next()
console.log(4)
})
app.get('/',function(req,res,next){
console.log(5)
// next()
console.log(6)
})
app.get('/new',function(req,res,next){
console.log(7)
next()
console.log(8)
})
app.listen(3003,()=>{
console.log('3003端口成功运行');
})
# 2.6 koa
get数据: cxt.params
post数据 cxt.request.body
返回数据给前台 cxt.body
安装依赖:
yarn add --save koa koa-static koa-router koa-bodyparser
# 2.6.1 koa示例:
const Koa = require('koa')
const static = require('koa-static'); //管理静态资源
const Router = require('koa-router'); //管理路由
const bodyParser = require('koa-bodyparser')
const path = require('path')//设置绝对路径需要用到
const app = new Koa()
const router = new Router();
//解析post数据
app.use(bodyParser());
//配置路由
app.use(router.routes()).use(router.allowedMethods());
app.use(static( path.join(__dirname,'public') ))
router.post('/heaven',cxt=>{
console.log('执行',cxt.request.body)
//返回数据
cxt.body = {
status:0,
data:{}
}
})
//动态路由
router.get('/:id',cxt=>{
// console.log('执行',cxt.params)
const {id} = cxt.params;
console.log(id);
})
app.listen(5001,()=>{
console.log('5001端口成功运行');
})
koa可以使用koa-cors包,允许跨域请求
yarn add koa-cors
app.use(cors());//允许跨域请求
# 2.7 使用koa-multer上传图片
# 2.7.1 form表单提交(form提交可以跨域)
<form action="http://localhost:3000/img/upload" method="post" enctype="multipart/form-data">
<input type="file" name="image" id='input'/>
<input type="submit" value='submit'>
</form>
# 2.7.2multer配置
相关依赖:
koa koa-bodyparser koa-static koa-multer koa-router
上传成功后,返回图片url
const Koa = require('koa')
const BodyParser = require('koa-bodyparser')
const Router = require('koa-router')
const Static = require('koa-static')
const multer = require('koa-multer')
const router = new Router()
const path = require('path')
const fs = require('fs')
const app = new Koa()
const {imgUpload} = require('./controller/imgController')
app.use(BodyParser());
app.use(router.routes())
app.use(Static(path.join(__dirname,'public')))
//文件上传配置
var storage = multer.diskStorage({
//文件保存路径
destination: function (req, file, cb) {
cb(null, 'public/uploads/')
},
//修改文件名称
filename: function (req, file, cb) {
const extname = path.extname(file.originalname); //拿到后缀名
cb(null, Date.now() + extname);
// cb(null, file.originalname);
}
})
//加载配置
var upload = multer({ storage: storage });
//上传地址,这里的images和form表单提交保持一致
router.post('/img/upload',upload.single('image'),imgUpload)
app.listen(3000,()=>{
console.log('3000端口开启成功')
})
imgUpload
exports.imgUpload = cxt=>{
//拿到保存的文件名,拼接目录路径
const {filename} = cxt.req.file
cxt.body = {
status:0,
msg:'图片上传成功',
data:{
name:filename,
url:`/uploads/${filename}`
}
}
}
# 2.8 Node.js Buffer 缓冲区
# 2.8.1 Buffer
Buffer 是存放二进制数据容器,类似 Python 的 Byte 类型。参考 - 字符编码 & Base64。
// utf-8 编码
jmjc_utf8 = new Buffer('简明教程', 'utf-8')
console.log(jmjc_utf8) // <Buffer e7 ae 80 e6 98 8e e6 95 99 e7 a8 8b>
// utf-8 解码
jmjc = jmjc_utf8.toString()
console.log(jmjc) // 简明教程
# 2.8.2 缓冲区
Buffer 除了转码的作用外,它更多时候还用作缓冲区,用于数据的缓存。
var buf = new Buffer(10) // 定义一个10字节的 Buffer
buf.write('...') // 缓存数据
console.log(buf) // <Buffer 2e 2e 2e 00 00 00 00 00 00 00>
console.log(buf.toString()) // ...
# 2.8.3 Base64
Buffer 的 toString 方法,还提供了 Base64 数据的转换。
var b = new Buffer('JavaScript')
var s = b.toString('base64')
// SmF2YVNjcmlwdA==
var b = new Buffer('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString()
// JavaScript
# 2.9 node事件循环机制
# 2.9.1 异步任务的分类
1.闳任务 macrotask
setTimeout的回调
setInterval的回调
2.微任务 microtask
- Promise.then的回调
# 2.9.2 执行机制
# 1.node中
先执行完 本次遇到的所有的闳任务
再执行本次遇到的微任务
# 2.浏览器端
先执行闳任务 并且把本次闳任务遇到的微任务执行完
再执行下一次的闳任务 并且把本次闳任务遇到的微任务执行完
如此循环
setTimeout(()=>{ //宏1
console.log('timer1');
Promise.resolve().then(function() { //微1
console.log('promise1')
})
Promise.resolve().then(function() { //微3
console.log('promise3')
setTimeout(()=>{
console.log('timer3')
},0)
})
}, 0)
setTimeout(()=>{ //宏2
console.log('timer2')
Promise.resolve().then(function() { //微2
console.log('promise2')
})
Promise.resolve().then(function() { //微4
console.log('promise4')
})
}, 0)
# 2.10 cookie和session
# 2.10.1 概念
# cookie和session
都是把数据储存起来储存时间的自已定义的,即使浏览器关闭了数据依旧会储存
cookie的原理
在用户第一次访问某个网站的时候,是不会携带cookie的,服务器会让浏览器再一次访问的时候必须携带指定的cookie。再第二次访问服务器的时候,如果浏览器携带的cookie和服务器要求的cookie是一样,则服务器就认识了指定的用户。
session的原理
在用户第一次访问某个网站的时候,是不会携带cookie的,服务器会让浏览器再一次访问的时候必须携带指定的cookie(A),同时还会在服务端生成一个session,这个session是以指定的cookie(A)为属性名的。再第二次访问服务器的时候,如果浏览器携带的cookie和服务器session中cookie属性名是一样。则服务器就认识了指定的用户
cookie特点
- 存储在浏览器
- 不安全
- 存储数据的量比较小 4M
session特点
- 依赖于cookie实现的
- 存储在服务端
- 安全
- 存储数据的量比较大
Storage也可以存储数据
localStorage
- 存储数据的时间:永久
- 如果浏览器卸载,数据才会消失
sessionStorage
- 存储数据的时间:一次浏览器窗口周期 ,打开浏览器窗口到关闭浏览器窗口的时间差
# 2.10.2 express的cookie
依赖:
yarn add --save cookie-parser
示例:
const express = require('express')
const cookieParser = require('cookie-parser')
const app = express()
app.use(cookieParser())
app.get('/',(req,res)=>{
//获取所有去过的城市
if(req.url==='/favicon.ico')return
const cityArr =JSON.parse(req.cookies.express_cookie_city||'[]')
res.send(`你的足迹是${cityArr}`)
})
app.get('/:city',(req,res)=>{
if(req.url==='/favicon.ico')return
//获取当前city
const {city} = req.params
//读取cookie
const cityArr = JSON.parse(req.cookies.express_cookie_city||'[]')
cityArr.push(city)
//使用res响应体对象 来让前台存储cookie
//res.cookie(属性名,属性值,cookie的存储时长)
res.cookie('express_cookie_city',JSON.stringify(cityArr),{
maxAge:1000*60*60*60,//存储时间为60个小时
})
res.send(`你今天去的城市是${city}`)
})
app.listen(3000,()=>{
console.log('3000端口成功运行');
})
# 2.10.3 express的session
const express = require('express')
const session = require('express-session')
const cookieParser = require('cookie-parser')
const app = express()
app.use(cookieParser())
app.use(session({
secret: 'keyboard cat',
resave: false,
name:'heaven', //设置的cookie的属性名
saveUninitialized: true,
cookie: {
secure: false,//可以不写
maxAge:80000,//必须
}
}))
app.get('/',(req,res)=>{
//获取所有去过的城市
if(req.url==='/favicon.ico')return
const cityArr = JSON.parse(req.session.express_session_city||'[]')
res.send(`你的足迹是${cityArr}`)
})
app.get('/:city',(req,res)=>{
if(req.url==='/favicon.ico')return
//获取当前city
const {city} = req.params
//读取session
const cityArr = JSON.parse(req.session.express_session_city||'[]')
//把这次去的地方添加到上次去的数组中
cityArr.push(city)
//设置session
req.session.express_session_city = JSON.stringify(cityArr)
res.send(`你今天去的城市是${city}`)
})
app.listen(3004,()=>{
console.log('3004端口成功运行');
})
# 2.10.4 koa2的cookie
const Koa = require('koa')
const router = require('koa-router')()
const app = new Koa()
//配置路由
app.use(router.routes()).use(router.allowedMethods())
router.get('/', async cxt => {
//读取cookie
const cityArr = JSON.parse(cxt.cookies.get('koa2_cookie_city') || '[]')
console.log(cityArr);
cxt.body = `你今天去的城市是${cityArr}`
})
router.get('/:city', async cxt => {
const {city} = cxt.params
//读取cookie
const cityArr = JSON.parse(cxt.cookies.get('koa2_cookie_city') || '[]')
//把这次去的地方添加到上次去的数组中
cityArr.push(city)
//cxt.cookies.set(属性名,属性值,时长)
cxt.cookies.set('koa2_cookie_city', JSON.stringify(cityArr), {
maxAge: 1000 * 60 * 60 * 60, //存储60个小时
})
cxt.body = `你今天去的城市是${city}`
})
app.listen(3000, () => {
console.log('3000端口成功启动')
})
# 2.10.5 koa2的session
const Koa = require('koa')
const router = require('koa-router')()
const session = require('koa-session')
const app = new Koa()
//配置koa-session
app.keys = ['some secret hurr'];
const CONFIG = {
key: 'heaven', /** (string) cookie key (default is koa:sess) **/
/** (number || 'session') maxAge in ms (default is 1 days) **/
/** 'session' will result in a cookie that expires when session/browser is closed **/
/** Warning: If a session cookie is stolen, this cookie will never expire **/
maxAge: 86400000,
autoCommit: true, /** (boolean) automatically commit headers (default true) **/
overwrite: true, /** (boolean) can overwrite or not (default true) **/
httpOnly: true, /** (boolean) httpOnly or not (default true) */
signed: true, /** (boolean) signed or not (default true) **/
rolling: false, /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) **/
renew: false, /** (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)**/
};
app.use(session(CONFIG, app));
//配置路由 在中间件的最下面
app.use(router.routes()).use(router.allowedMethods())
router.get('/',async cxt=>{
if(cxt.url==='/favicon.ico')return
//读取session
const cityArr = JSON.parse(cxt.session.koa2_session_city||'[]')
cxt.body = `你今天去的城市是${cityArr}`
})
router.get('/:city',async cxt=>{
if(cxt.url==='/favicon.ico')return
const {city} = cxt.params
//读取session
const cityArr = JSON.parse(cxt.session.koa2_session_city||'[]')
//把这次去的地方添加到上次去的数组中
cityArr.push(city)
// console.log(cityArr);
//设置session
cxt.session.koa2_session_city = JSON.stringify(cityArr)
cxt.body = `你今天去的城市是${city}`
})
app.listen(3002,()=>{
console.log('3002端口成功启动')
})
# 2.11 SPA单页应用刷新404问题
React,Vue都是单页面SPA应用,前台路由是不会发起网络请求的,但是F5刷新会发起请求。此时由于后台根本没有对应的中间件处理函数,刷新引起的请求得不到响应,404。
解决方案:模拟脚手架功能。本地开发的时候F5刷新,脚手架给我们返回了一个index.html
项目整合后,我们可以在后台代码中模拟
// 配置前台路由 把前台打包放到Public目录下,可解决单页面刷新问题
app.use(cxt=>{
cxt.set('Content-Type','text/html;charset=UTF-8')
const data = fs.readFileSync(__dirname+'/public/index.html')
cxt.body = data
})
# 2.12 linux下快速删除
当我们在linux
系统中要删除数万或者数十万甚至数百万的文件时使用rm -rf *
就不太好用,因为要等待很长一段时间。在这种情况之下我们可以使用linux
系统命令rsync
来巧妙的处理。rsync
实际上用的是替换原理,处理数十万个文件也是秒删。
1.先新建一个空目录用于替换
mkdir /data/blank
2.用rsync快速替换实现清空文件夹(绝对路径)
rsync --delete-before -d -a -H -v --progress --stats /data/blank/ /var/edatacache/
# 或者
rsync --delete-before -d /data/blank/ /var/edatacache/
这样edatacache就被清空了
选项说明:
–delete-before 接收者在传输之前进行删除操作
–progress 在传输时显示传输过程
-a 归档模式,表示以递归方式传输文件,并保持所有文件属性
-H 保持硬连接的文件
-v 详细输出模式
–stats 给出某些文件的传输状态
-d transfer directories without recursing
3.也可以用来删除大文件
假如我们在/root/下有一个几十G甚至上百G的文件data,现在我们要删除它
创建一个空文件
touch /root/empty
用rsync清空/root/data文件
rsync --delete-before -d --progess --stats /root/empty /root/data
当SRC和DEST文件性质不一致时将会报错 当SRC和DEST性质都为文件【f】时,意思是清空文件内容而不是删除文件 当SRC和DEST性质都为目录【d】时,意思是删除该目录下的所有文件,使其变为空目录