Node学习笔记

前言:

        node.js  是一个基于 V8 javaScript引擎的JavaScript运行时环境

        在chrome浏览器,还需要 解析,渲染html , CSS 相关引擎, 支持浏览器相关操作的api,

浏览器自己的事件循环

        同样,在node.js中,也包含了一些额外的操作,比如文件系统的读写 ,网络的IO ,加密, 压缩文件的操作

node 架构

Node.js技术架构 - 掘金 (juejin.cn)

一、fs模块

File system | Node.js v20.10.0 Documentation (nodejs.org)

01、认识

        对于服务端通常都会用自己的文件系统,服务端需要将各种数据,文件,图片放到不同的地方,数据大多数放在数据库,而配置文件,用户资源, 图片,视频和音频 都是以文件的形式存放在操作系统上的

02、API介绍

2.1、api的3种操作方式

        方式一、同步方式,会阻塞后续代码的运行

        方式二、异步回调:代码不会被阻塞,需要传入回调函数

        方式三、异步Promise操作文件,返还一个Promise对象

2.2、读写

2.3、目录

        读取目录下的文件可以使用 递归读取

二、events模块

01、基本使用

const EventEmitter = require('node:events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');

02、API 

三、Buffer

Buffer | Node.js v20.10.0 Documentation (nodejs.org)

01、Buffer类

//创建buffer

const  buf =  Buffer.from()


const buf = Buffer.alloc(size[,file[,encoding]])

     在创建buffer时,直接创建一个pool(Buffer | Node.js v20.10.0 Documentation (nodejs.org)),8kb , 如果剩余长度不够填充,才会新创建createPool, 如果够使用,就直接使用, 之后使用poolOffset

02、Blob类

四、stream

01、认识

02、Node.js中的4种流

 03、可读流的基本使用:

        

cosnt  fs = require('fs')

//通过流读取文件

const  readstream  =   fs.createReadStream('aaa.txt' ,()=>{
 start : 8,
end : 22 ,
highWaterMark : 3
}
)

//监听读取过来的数据

readstream.on('data' , (data)=>{
    console.log(data.toString())
})


//监听文件打开事件, 传入一个参数fd  文件描述符
readstream.on('open' , (fd)=>{
    
})

//监听文件关闭事件
readstream.on('close',()=>{
        
})

04、可写流

05、pipe

  

readstream.pipe(writestrream)

五、http (可以开发服务器)

01、创建http

const http = require('node:http');

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);

        可以创建多个端口,每一个端口提供不同的服务,

        server.listen()函数有不同的参数,具体看文档Net | Node.js v20.10.0 Documentation (nodejs.org)

注意:访问localhost:8000访问了2次

        第一次访问:localhost:8000

        第二次访问: localhost :8000/favicon.ico (浏览器的默认行为)

02、nodemon

        作用:监测服务器文件发生改变,重启服务器

03、request

3.1、req携带的数据的分析:

        url, query    (这里想得到req的,使用url , 和 querstring 'qs')处理即可

3.2、req的本质是一个可读流,传入的数据

        通过使用req.on('data',()=>{

        })可以拿到传入req对象的body数据

3.3、登陆原理


const http = require('http')

const server = http.createServer((req,res)=>{

        
    //req 的本质是一个可写流, 如果不设置编码格式,会以二进制形式

    req.setEncoding('utf-8')


    //拿到req传递的数据
    //如果数据在body中
    req.on('data', ()=>{
        
        //和服务器端的数据进行比较
        //判断是否成功
    })

    
    req.on('end',()=>{
    // xxx
    })
})

3.4、请求头Header

content-type

content-length:  文件的大小长度

keep-alive:

accept-encoding :

告诉服务器客户端支持的文件压缩格式, 比如 js文件压缩的gzip  .gz文件 ,通常使用默认值即可

accept : 

告诉服务器,客户端可以接受的普通的文件格式

user-agent

客户端的相关信息

3.5、Authorization

        用来设置token,用来验证

04、response

4.1、res本质是一个可写流

        如果希望客户端返回数据

res.write('msg')  //直接写出的数据 , 但是可写流是没有关闭的
res.end('。。。。')  //最后写出的数据 ,但是需要手动关闭 ,
//如果没有end ,客户端会一致等待 , 需要在给请求设置超时时间

4.2、响应状态码

常见的状态码:

HTTP 响应状态码 - HTTP | MDN (mozilla.org)

HTTP 响应状态码用来表明特定 HTTP 请求是否成功完成。 响应被归为以下五大类:

  1. 信息响应 (100199)
  2. 成功响应 (200299)
  3. 重定向消息 (300399)
  4. 客户端错误响应 (400499)
  5. 服务端错误响应 (500599)

设置状态码;

//1\
res.statuscode =  401 


//2 

res.writeHead(401,{

})

4.3、响应头

设置头

res.setHeader('content-type' , 'application/json ; charset=utf8)

res.serHeader(200, {
    'content-type' :'application/json ;
})

05、node中的axios ,nodemon

        axios库可以在浏览器中使用,也可以在Node中使用

        在浏览器,axios使用的是封装的xhr

        在Node,使用的是内置的http模块封装

        nodemon, node moniter , 监控浏览器的资源是否改变,改变就重启浏览器

        安装:  npm install nodemon -g  (全局安装)

06、使用http发送网络请求

const http = require('http')

http.get('http://localhost:8000' , res=>{

    res.on('data', data=>{
        console.log(Json.parse(data.toString()))
    })
})


//和服务器建立一个可读流,写入一些东西
const req = http.request( {
    method:'POST',
    hostname:'localhost',
    port : 8000
}, res =>{
    res.on('data', data=>{
        console.log(Json.parse(data.toString()))
    })
})

//注意post请求要 调一下end()表示写入结束
req.end()

07、文件上传

使用 Node.js 的 http 模块处理文件上传 - 掘金 (juejin.cn)

        上传文件多是用form-data格式

       可写流中包含了其他数据,使用字符串处理,将图片对应的二进制串,单独的保存在文件中

const http = require('http')
const fs = require('fs')

const server = http.createServer((req, res) => {
  req.setEncoding('binary')
  const boundary = req.headers['content-type'].split('boundary=')[1]
  let reqData = ''
  req.on('data', data => {
    reqData += data
  })
  req.on('end', () => {
    const imgType = 'image/png'
    const imgDataStartIndex = reqData.indexOf(imgType) + imgType.length
    const imgDataEndIndex = reqData.indexOf(`--${boundary}--`)
    const imgData = reqData.substring(imgDataStartIndex, imgDataEndIndex).trim()
    fs.writeFile('./img.png', imgData, 'binary', err => {
      if (!err) console.log('图片写入成功')
    })
    res.end('上传成功')
  })
})

server.listen(3010, () => console.log('服务器开启'))

08、浏览器上传文件到Node服务器

六、后续

七、express(开发服务器)

01、搭建express

npm init 

npm install 

        main.js

const express = require('express')

const  app = express()


app.get('/',(res ,req)=>{
    res.end('访问成功')
})

app.post('/',(req , res)=>{
    res.end('成功')
})


app.listen(3000 , ()=>{
    console.log('端口启动')    
})

02、中间件

编写中间件 - Express 中文文档 (nodejs.cn)

简单来说,就是给express传递的回调函数就是中间件

中间件函数是在应用程序的请求-响应周期中可以访问 请求对象 (req)、响应对象 (res) 和 next 函数的函数。next 函数是 Express 路由中的一个函数,当被调用时,它会在当前中间件之后执行中间件。

中间件函数可以执行以下任务:

  • 执行任何代码。
  • 更改请求和响应对象。
  • 结束请求-响应周期。
  • 调用堆栈中的下一个中间件。

如果当前中间件函数没有结束请求-响应循环,它必须调用 next() 将控制权传递给下一个中间件函数。否则,请求将被挂起。

下图显示了中间件函数调用的元素:

中间件函数适用的 HTTP 方法。

中间件函数适用的路径(路由)。

中间件函数。

中间件函数的回调参数,按约定称为 "next"。

中间件函数的 HTTP response 参数,按约定称为 "res"。

中间件函数的 HTTP request 参数,按约定称为 "req"。

从 Express 5 开始,返回 Promise 的中间件函数在拒绝或抛出错误时将调用 next(value)next 将使用被拒绝的值或抛出的错误来调用。

03、编写中间件

const  express  = require('express')

const app = express()

//通过use注册的中间件是最简单的中间件

app.use((req, res, next)=>{
    
    next()
})

app.use((req, res, next)=>{
    
    //上一个中间件,执行了next方法,才会运行到这里,对于一个中间件,不是end(),就next()
    //这一点上边提到, 如果 没有next() 和 end() 就会被 挂起
})


app.listen(3000,()=>{})

  路径匹配中间件


app.use('/path' , (req ,res , next) =>{
     //中间件的逻辑
    res.end(data)
})

   路径和方法匹配中间件

app.get('/path' , (req ,res , next )=>{
    
    //中间件的相关逻辑
    res.end(data)
} )

注册多个中间件

app.method('/path',中间件1 , 中间件2 ,...)

        多个匹配的中间件是否执行,取决与第一个中间件是否为next()

04、应用中间件

应用 - Express 中文文档 (nodejs.cn)

      4.1、  req传入数据格式处理,res.body如何获取

const express = require('express')

const app=  express()


/**
* 想要在res.body中得到传入的数据, 要使用中间件对res携带的数据解析
/

//如果使用的是json格式的

app.use(exxpress.json())

//如果传入的是urlencoded 格式的,使用
app.use(express.urlencoded()) 


//如果传入的是formdata, 使用muleter

app.use(multer().any)

//需要注意的是, 默认使用的是querystring模块,有点老,控制台会出警告
//改为使用qs第三方库
app.use(express.urlencoded({extended:true})) 


app.post('/login',(req,res,next)=>{

    
})



app.listen(8000,()=>{
    console.log('端口已启动')
})

4.2、日志中间件morgan

// npm install morgan


const express = require('express')


const fs = require('fs')

const morgan = require('morgan')



const app=  express()

const writeStream =  fs.createWriteStream('path')

app.use(morgan('combined'),{stream :  writeStream})

app.post('/login',(req,res,next)=>{

    
})



app.listen(8000,()=>{
    console.log('端口已启动')
})

4.3、文件上传 multer

// npm install multer


const express = require('express')


const fs = require('fs')

const morgan = require('multer')



const app=  express()


const upload = multer({
    dest:'./upload'
})

const upload = multer({
    storage: multer.diskStorage({
        destination(req,file,cb){
            cb(null, '你要存的地方')
        },
        filename(req,file,cb){
            cb(null, '自定义的文件名'+file.originalname)//自定义的文件名 + 文件原来的后缀名
        }
    })
})

//传入单个文件
app.post('/login',  upload.single('传入的属性名')  ,(req,res,next)=>{

     console.log(res.file)
})

//传入多个文件
app.post('/login',  upload.array('传入的属性名')  ,(req,res,next)=>{

     console.log(res.file)
})



app.listen(8000,()=>{
    console.log('端口已启动')
})

05、express路由

express.Router

使用 express.Router 类创建模块化、可安装的路由处理程序。一个Router实例是一个完整的中间件和路由系统;因此,它通常被称为 "mini-app"。

以下示例将路由创建为模块,在其中加载中间件函数,定义一些路由,并将路由模块安装在主应用程序的路径上。

在app目录下创建一个名为birds.js的路由文件,内容如下:

const express = require('express')
const router = express.Router()

// middleware that is specific to this router
router.use((req, res, next) => {
  console.log('Time: ', Date.now())
  next()
})
// define the home page route
router.get('/', (req, res) => {
  res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
  res.send('About birds')
})

module.exports = router

然后,在应用程序中加载路由模块:

const birds = require('./birds')

// ...

app.use('/birds', birds)

06、express部署静态资源服务器

        部署静态资源服务器的方式有很多,比如说nigax,tomcat等

        

app.use(express.static('文件名'))

07、express错误处理

        

错误处理 - Express 中文文档 (nodejs.cn)

08、express源码学习

        后续补充

八、koa (开发服务器)

Koa (koajs) -- 基于 Node.js 平台的下一代 web 开发框架 | Koajs 中文文档 (bootcss.com)

01、content

        和express一样,koa使用app.use()调用中间件,但是koa的中间件只接受2个参数,

app.use((ctx,next)=>{
    //中间件的相关逻辑
})

Koa Context 将 node 的 request 和 response 对象封装到单个对象中,为编写 Web 应用程序和 API 提供了许多有用的方法。 这些操作在 HTTP 服务器开发中频繁使用,它们被添加到此级别而不是更高级别的框架,这将强制中间件重新实现此通用功能。

_每个_ 请求都将创建一个 Context,并在中间件中作为接收器引用,或者 ctx 标识符,如以下代码片段所示:

app.use(async ctx => {
  ctx; // 这是 Context
  ctx.request; // 这是 koa Request
  ctx.response; // 这是 koa Response
});

为方便起见许多上下文的访问器和方法直接委托给它们的 ctx.request或 ctx.response ,不然的话它们是相同的。 例如 ctx.type 和 ctx.length 委托给 response 对象,ctx.path 和 ctx.method 委托给 request

        注意:

02、koa-router路由

         原来是第三方库,但是很久没维护,官方维护了一个库

03、koa参数的传递和解析

        

const koa = reuqire('koa')

const userRouter = new koaRouter({ prefix : '/users'})


// 参数传递的5种方式
// get: params ,  /:id
// get: query  , ?name=value&&key=da
// post: json ,   { k:v , k:v}
// post: x-www-from-urlencoded
// post: from-data

1/params
userRouter.get('/:id',(ctx , next)=>{
    const id = ctx.params.id
    ctx.body =  'users data ' + id 
})

2/query
userRouer.get('/',(ctx,next)=>{
    const query = ctx.query
    ctx.body = ''+ JSON.stringfy(query)
})

3/json

//使用koa-bodyparser 中间件 , 需要安装

npm install koa-bodyparser

app.use(bodyParser())
app.use((ctx,next)=>{
  //    ctx.request.body   就是传递过来的数据
    ctx.body   // 是放在request对象里的
})

4/urlencoded

//同样使用中间件,
//使用koa-bodyparser 中间件 , 需要安装

npm install koa-bodyparser 

//和 json 的处理方式一样



5/from-data

//解析body中的数据,需要使用multer
//安装依赖 npm install koa-multer
// 使用multer中件件

const  upload = multer({
    //options
})

app.use(upload.any())

app.use((ctx,next)=>{
    ctx.request.body // 就是传递过来解析号的from-data数据
})





04、koa文件上传

05、静态服务器

        使用第三方库,

        npm  install koa-static

      

const  Koa = require('koa')
const static  = require('koa-static')
const app = new Koa()

//不同于express, koa内部没有部署相关的功能
// express  ,   app.use(express.static('./build'))
// koa     ,    安装第三方库koa-static后,调用即可
app.use(static('./build'))

app.listen(8000, ()=>{
    console.log('静态服务器开启成功')
})

06、响应数据的方式

输出结果:body将作为响应主题

string ,buffer, Stream , Object||Array , null ,

如果response.status没有设置, koa会自动将状态设置为200或者204        

        设置status,ctx.status = 200  

                            ctx.response.status = 204

07、错误处理

const koa = require('koa')
const app = new koa()

app.use((ctx,next)=>{
    ctx.app.emit(''error' , new Error('errorMsg') , ctx)

    //触发error事件,处理错误
})

app.on('error',(err ,ctx)=>{
    console.log(err.message)
    
    //根据不同的错误码返回不同的数据
    
    switch(ctx.body.code)
    
})

app.listen(8000,()=>{
    console.log('服务器启动成功')
})

08、koa源码学习

09、和express的比较

再也不怕面试官问你express和koa的区别了 - 掘金 (juejin.cn)

        架构方面:

        express内置很多的功能更完善

        koa是更加简洁和自由的,只包含了最核心的功能,不会对我们使用的其他中间件进行任何的限制

        相同点:

        他们的核心都是中间件,对于同步操作,他们的执行顺序是一样的,但是异步操作的执行逻辑略有不同

10、koa,express执行同步和异步代码的逻辑

        同步

app.use((ctx,next)=>{
    ctx. msg = 'aaa'
    next()
    console.log('ctx.msg')  //  aaabbbccc
})

app.use((ctx,next)=>{
    ctx. msg += 'bbb'
    next()
    
})

app.use((ctx,next)=>{
    ctx. msg += 'ccc'
    next()
   
})

        异步

app.use((ctx,next)=>{
    ctx. msg = 'aaa'
    next()
    console.log('ctx.msg')  //  aaabbb , koa如果下一个中间件是一个异步函数,koa默认不会等到下一个函数的结果,就会直接执行下一步的操作
})

app.use((ctx,next)=>{
    ctx. msg += 'bbb'
    next()
    
})

app.use( async (ctx,next)=>{
    
    const data = await  axios.get('')
    ctx.msg+= data
    next()
   
})



//如果需要等待异步函数的执行结果,需要在next函数前+await, 中间件函数前加上 async

app.use( async (ctx,next)=>{
    ctx. msg = 'aaa'
    await next()
    console.log('ctx.msg')  //  aaabbb'data的数据'
})

app.use( async (ctx,next)=>{
    ctx. msg += 'bbb'
    await next()
    
})

app.use( async (ctx,next)=>{
    
    const data = await  axios.get('')
    ctx.msg+= data
    next()
   
})



express执行同步的逻辑和koa的方式一样

执行异步的逻辑不同,

koa的next返回的是一个promise,可以使用await

但是express 的next返回的void,  await next()是不会等待异步函数执行结果

所以express, 返回结果,只能在异步函数的后面返回结果

11、洋葱模型

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值