理解stream
可读流可理解为:从一个装满了水的水桶中一点一点把水抽取出来的过程
可写流可理解为:把从可读流抽出来的水一点一点倒入一个空的桶中的过程
标准输入输出
// 标准输入输出
process.stdin.pipe(process.stdout)
const http = require('http')
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
req.pipe(res) // 最主要 直接留到res里面
}
})
server.listen(8000)
复制文件
第一个水桶readStream、第二个水桶writeStream、通过pipe 这个管道链接起来
readStream读取文件 是一点点读取的 ondata 可以监听每一次的读取内容
readStream读取文件 是一点点读取的 !!!(不一定是一行行的读!!!!)
// 复制文件
const fs = require('fs')
const path = require('path')
读取本地文件
const fileName1 = path.resolve(__dirname, 'data.txt')
const fileName2 = path.resolve(__dirname, 'data-bak.txt')
const readStream = fs.createReadStream(fileName1)
const writeStream = fs.createWriteStream(fileName2)
readStream.pipe(writeStream)
第一个水桶readStream、第二个水桶writeStream、通过pipe 这个管道链接起来
readStream读取文件 是一点点读取的 !!!(不是一行行的读!!!!)
ondata 可以监听每一次的读取内容
readStream.on('data', chunk => {
console.log(chunk.toString())
})
readStream.on('end', () => {
console.log('copy done')
})
const http = require('http')
const fs = require('fs')
const path = require('path')
const fileName1 = path.resolve(__dirname, 'data.txt')
const server = http.createServer((req, res) => {
if (req.method === 'GET') {
const readStream = fs.createReadStream(fileName1)
readStream.pipe(res)
}
})
server.listen(8000)
实际应用
log.js
const fs = require('fs')
const path = require('path')
// 写日志
// io 有网络io 也有文件io io 相对于 cpu计算和读写内存来说 就是比较慢!
function writeLog(writeStream, log) {
writeStream.write(log + '\n') // 关键代码
}
// Stream 是一种 流 详细查看stream-test 文件夹
// 生成 write Stream __dirname 当前目录
function createWriteStream(fileName) {
const fullFileName = path.join(__dirname, '../', '../', 'logs', fileName)
const writeStream = fs.createWriteStream(fullFileName, {
flags: 'a' // 意思是追加不是覆盖
})
return writeStream
}
// 写访问日志
const accessWriteStream = createWriteStream('access.log')
function access(log) {
writeLog(accessWriteStream, log)
}
module.exports = {
access
}
app.js 入口文件 记录 access log
// 入口文件
const querystring = require('querystring') //node.js提供的原生模块
const { get, set } = require('./src/db/redis')
const { access } = require('./src/utils/log') //引入写日志方法
const handleBlogRouter = require('./src/router/blog')
const handleUserRouter = require('./src/router/user')
// 获取 cookie 的过期时间
const getCookieExpires = () => {
const d = new Date()
d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
console.log('d.toGMTString() is ', d.toGMTString())
return d.toGMTString()
}
// 用于处理 post data
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if (req.method !== 'POST') { //不是post 返回{}
resolve({})
return
}
if (req.headers['content-type'] !== 'application/json') { //如果不是json 也是返回{}
resolve({})
return
}
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (!postData) {
resolve({})
return
}
resolve(
JSON.parse(postData)
)
})
})
return promise
}
const serverHandle = (req, res) => {
// 记录 access log
access(`${req.method} -- ${req.url} -- ${req.headers['user-agent']} -- ${Date.now()}`)
// 设置返回格式 JSON
res.setHeader('Content-type', 'application/json')
// 获取 path
const url = req.url
req.path = url.split('?')[0]
// 解析 query
req.query = querystring.parse(url.split('?')[1])
// 解析 cookie
req.cookie = {}
const cookieStr = req.headers.cookie || '' // k1=v1;k2=v2;k3=v3
cookieStr.split(';').forEach(item => {
if (!item) {
return
}
const arr = item.split('=')
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
// 解析 session (使用 redis)
let needSetCookie = false
let userId = req.cookie.userid
if (!userId) {
needSetCookie = true
userId = `${Date.now()}_${Math.random()}`
// 初始化 redis 中的 session 值
set(userId, {})
}
// 获取 session
req.sessionId = userId
get(req.sessionId).then(sessionData => {
if (sessionData == null) {
// 初始化 redis 中的 session 值
set(req.sessionId, {})
// 设置 session
req.session = {}
} else {
// 设置 session
req.session = sessionData
}
// 处理 post data
return getPostData(req)
})
.then(postData => {
req.body = postData
const blogResult = handleBlogRouter(req, res)
if (blogResult) {
blogResult.then(blogData => {
if (needSetCookie) {
// httponly 前端不能修改 只能后端修改
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(blogData)
)
})
return
}
const userResult = handleUserRouter(req, res)
if (userResult) {
userResult.then(userData => {
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(userData)
)
})
return
}
// 未命中路由,返回 404
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found\n")
res.end()
})
}
module.exports = serverHandle
扩展知识1
linux的crontab命令,就是定时任务,项目本地开发不需要处理,一般都是公司的运维去处理
扩展知识2
日志分析:const readline = require('readline');nodejs提供的一行行的读取日志; 了解即可!!!
const fs = require('fs')
const path = require('path')
const readline = require('readline')
// 文件名 逐行读取
const fileName = path.join(__dirname, '../', '../', 'logs', 'access.log')
// 创建 read stream
const readStream = fs.createReadStream(fileName)
// 创建 readline 对象
const rl = readline.createInterface({
input: readStream
})
let chromeNum = 0
let sum = 0
// 逐行读取
rl.on('line', (lineData) => {
if (!lineData) {
return
}
// 记录总行数
sum++
const arr = lineData.split(' -- ')
if (arr[2] && arr[2].indexOf('Chrome') > 0) {
// 累加 chrome 的数量
chromeNum++
}
})
// 监听读取完成
rl.on('close', () => {
console.log('chrome 占比:' + chromeNum / sum)
})