当前位置: 首页 > article >正文

Node.js学习记录(二)

目录

一、express

1、初识express

2、安装express

3、创建并启动web服务器

4、监听 GET&POST 请求、响应内容给客户端

5、获取URL中携带的查询参数

6、获取URL中动态参数

7、静态资源托管

二、工具nodemon

三、express路由

1、express中路由

2、路由的匹配

3、路由模块化

4、路由模块添加前缀

四、中间件 

1、express中间件

2、express中间件调用流程

3、中间件格式

4、创建并使用中间件函数

全局生效中间件

局部生效中间件

5、中间件作用

6、中间件分类

express.json & POST请求数据的接收

7、自定义中间件

五、Express 编写接口

1、编写get 、post 方式接口

2、cors 解决跨域

3、关于 cors

cors 响应头

Access-Control-Allow-Origin

Access-Control-Allow-Headers

Access-Control-Allow-Methods

cors请求分类

4、JSONP

5、express中使用session

6、express中使用 JWT生成token


Node.js学习记录(一)-CSDN博客

接着上一篇继续学习node.js

一、express

1、初识express

express类似node.js中http模块,专门用来创建WEB服务器的,相对node中http更加方便、功能更加强大;本质是npm上提供的第三方包。官网地址:Express - 基于 Node.js 平台的 web 应用开发框架 - Express中文文档 | Express中文网

express是基于node.js封装出来的,使用express可以快速创建这两种服务器。

2、安装express

npm i express@4.17.1 //安装指定版本
npm i express //不指定版本直接安装

3、创建并启动web服务器

先新建个express练习目录 express, 里面新建express_test.js

(顺便 npm init -y  初始化一个package.json 文件,后面会用  )

//导入express
const express = require('express')
//创建服务器
const app = express()
//启动服务器
app.listen(3000,()=>{
    console.log('服务器启动了')
})

4、监听 GET&POST 请求、响应内容给客户端

//导入express
const express = require('express')
//创建服务器
const app = express()

//监听请求,并向客户端响应数据 (指定user页面)
app.get('/user',(req,res)=>{
  res.send('hello express')
})
app.post('/user',(req,res)=>{
  res.send({name:'张三',age:18})
})

//启动服务器
app.listen(3000,()=>{
  console.log('服务器启动了 http://127.0.0.1:3000')
})

请求中的两个参数:req 请求对象、res 响应对象

用 app.get 监听get请求,app.post 监听post请求

通过res.send() 向客户响应数据

运行结果

5、获取URL中携带的查询参数

可以通过req.query对象查询  如链接:http://127.0.0.1:3000/user?id=1&name=test&str=%E5%AD%97%E7%AC%A6

//监听请求,并向客户端响应数据
app.get('/user',(req,res)=>{
  res.send('hello express')
  console.log('请求的参数:',req.query)
})
app.post('/user',(req,res)=>{
  res.send({name:'张三',age:18})
  console.log('请求的参数:',req.query)
})

6、获取URL中动态参数

通过req.params对象访问URL中通过匹配到的动态参数

默认req.params是一个空对象, 示例链接:http://127.0.0.1:3000/user/9?id=1&name=test&str=%E5%AD%97%E7%AC%A6

//导入express
const express = require('express')
//创建服务器
const app = express()

//监听请求,并向客户端响应数据 
//app.get('/user/:id/:name',(req,res)=>{
app.get('/user/:id',(req,res)=>{
  res.send('hello express')
  console.log('请求的动态参数参数:',req.params)
})

//启动服务器
app.listen(3000,()=>{
  console.log('服务器启动了 http://127.0.0.1:3000')
})

:<key> ,这个key起什么名字,打印里面就会得到什么,比如 :name ,打印就会得到{name:9},

:<key1>/:<key1>参数可以有多个,如 http://127.0.0.1:3000/user/9/test?id=1&name=test&str=%E5%AD%97%E7%AC%A6

7、静态资源托管

express 提供了express.static(),可以方便地创建一个静态资源服务器,如:可以通过代码将图片、css、js等文件对外开放访问

app.use(express.static('public'))

express在指定静态目录下查找文件,并提供对外访问路径,但存放静态文件的目录名不会出现在url中。

如下面示例中托管images和other文件夹后,访问里面的文件

images文件夹中图片:http://localhost:3000/1.png

other文件夹中css文件:http://localhost:3000/reset.css

(查找顺序是按照代码中写的顺序进行查找文件)

const express = require('express')
const app = express()
//托管images文件夹
app.use(express.static('./images'))
//如果托管多个就继续添加,如:托管other目录
app.use(express.static('./other'))

app.listen(3000, () => {
    console.log('Server is running here: http://localhost:3000')
})

挂载路径前缀

如果想要再访问的路径前有个前缀,则可以通过代码设置,访问地址http://localhost:3000/public/reset.css

//app.use('/前缀名字自己起',express.static('要托管的资源'))
app.use('/public',express.static('./other'))

二、工具nodemon

每次修改代码都需要重启服务,nodemon工具会监听代码变化,当代码有修改保存会自动重启,不用手动重启项目

1、安装nodemon

npm i -g nodemon 

2、执行

//安装nodemon 之前执行方式  :node node.js
//安装后
nodemon node.js

三、express路由

1、express中路由

客户端的请求与服务器处理函数之间的映射关系

//app.请求类型(请求url,处理函数)
//app.METHOD(PATH,HANDLER)
app.get('/', (req, res) => {
    res.send('hello word')
})

 

2、路由的匹配

每一个请求到达服务器,都需要先经过路由匹配,只有匹配成功才会调用对应的处理函数;

匹配时会按照路由顺序进行匹配,如果请求的类型和URL同时匹配成功,express才会将这次请求转给对应的function进行处理

3、路由模块化

为了方便对路由进行模块化管理,express不建议将路由直接挂载到app上,推荐抽离为单独的模块。

①、新建路由文件router.js

//express/router.js
const express = require('express')
//导入路由对象
const router = express.Router()

//挂载具体路由
router.get('/user/list', (req, res) => {
  res.send('get user list')
})
router.post('/user/add', (req, res) => {
  res.send('add user')
})
//导出路由
module.exports = router

②、注册并使用路由模块

//express/express_test.js
const express = require('express')
const useRouter = require('./router')//引入路由文件
const app = express()

//注册路由
app.use(useRouter)

app.listen(3000, () => {
    console.log('Server is running http://localhost:3000')
})

app.use() 这个函数作用是用来注册全局中间件

4、路由模块添加前缀

和静态资源托管类似(在一大类7小条中),添加一个统一访问前缀

//如添加统一前缀 api
// 把 ② 中代码 app.use(useRouter) 变更如下
app.use('/api',useRouter)

四、中间件 

1、express中间件

2、express中间件调用流程

当一个请求到达express服务器后,可以连续调用多个中间件,从而对这次请求进行预处理

3、中间件格式

本质上是function处理函数

中间件函数的形参列表中,必须包含 next 参数,而路由处理函数中 只包含req、res。

next函数的作用:是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由

当前中间件处理完了调用next() 后就会转交给下一个中间件

4、创建并使用中间件函数

全局生效中间件

客户端发起请求到达服务器之后,都会触发的中间件,叫全局生效的中间件。

使用app.use(中间件函数) ,即自定义一个全局生效的中间件

const express = require('express')
const app = express()

//自定义一个中间件 并注册使用
// const mn = function(req,res,next){
//     console.log('定义一个中间件')
//     next()
// }
// //注册使用中间件
// app.use(mn)

//或者直接简化
app.use(function(req,res,next){
    console.log('定义一个中间件')
    next()
})

app.listen(3000, () => {
    console.log('Server is running http://localhost:3000')
})

如果定义多个全局中间件,会按照中间件定义先后顺序依次进行调用。

局部生效中间件

不使用app.use()定义的中间件叫局部中间件;只对某个路由生效的中间件,不会影响其他路由。

局部中间件可以写多个或单个,多个用逗号隔开(多个也可以是数组形式)。

app.get('/',mn1, mn2,mn3,(req, res) => { res.send('Hello World') })

app.get('/',[mn1, mn2,mn3],(req, res) => { res.send('Hello World') })

//express\express_test.js
const express = require('express')
const app = express()
//定义一个局部中间件
const mn = function(req, res, next) {
    console.log('这是局部中间件')
    next()
}

//局部生效的中间件
//app.get(URL,局部中间件参数, (req, res) => {

//定义一个get路由
app.get('/',mn, (req, res) => {
    res.send('Hello World1')
})
app.post('/',(req, res) => {
    res.send('Hello World2')
})

app.listen(3000, () => {
    console.log('Server is running http://localhost:3000')
})

当访问get路由时会执行打印,访问post路由时不会执行。

5、中间件作用

多个中间件之间共享一个 req 和 res, 这样可以在上游的中间件中统一为 req和res 添加自定义属性或方法,供下游中间件或路由使用

如:在中间件中获取当前时间,把获取的时间挂到req的startTime属性上,在路由中也可以获取到这个时间。

中间件注意事项:

1、必须在路由之前注册中间件

2、执行完中间件代码后,一定不要忘记调用 next() 函数

3、防止代码混乱,调佣next()函数后不要在写额外代码

4、错误级别中间件必须注册在所有路由之后

6、中间件分类

express.json & POST请求数据的接收

如果是post请求,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据。

默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined。

如果不使用express.json()、express.urlencoded()可以使用三方的一个中间件:body-parser 来解析请求体数据

注:express内置的中间件express.urlencoded 就是基于 body-parser 这个三方中间件进一步封装出来的

const express = require('express')
const app = express()

//解析json格式的请求数据
app.use(express.json())

//解析表单数据和 url-encoded 格式的请求数据
app.use(express.urlencoded())

app.post('/',(req, res) => {
    console.log(req.body)
    res.send({"name":"John"})
})

app.listen(3000, () => {
    console.log('Server is running http://localhost:3000')
})

//1.导入解析表单数据的中间件 body-parserconst 
const parser = require('body-parser')

//2.使用 app.use()注册中间件
app.use(parser.urlencoded({extended: false})

7、自定义中间件

 

const express = require('express');
const app = express()
const qs = require('querystring')//node内置模块 解析和格式化网址查询字符串
app.use((req,res,next)=>{
    let str = ''
    req.on('data',(chunk)=>{
        console.log('data事件====',chunk)
        str += chunk
    })
    req.on('end',()=>{
        console.log('end事件====',str)
        console.log(qs.parse(str)) //解析出传递数据

        next()//调用next()函数
//注意要放在req.on('end', ...) 内部的回调函数中,需要在数据完全接收并解析后再继续处理请求
    })

})
app.post('/user',(req,res)=>{
    res.send(req.body)//响应给客户端接收到的数据
})
app.listen(3000,()=>{
    console.log('server is running http://localhost:3000')
})

 使用postman发起post请求并传递4个参数,运行结果如下,返回结果可以使用node内置模块querystring进行把字符串解析成json

如果要实现自定义中间件模块化,实现步骤类似express路由模块化类似,这里就不写具体步骤了~

五、Express 编写接口

准备工作 :新建apiRouter.js

目录结构

G:\myproject\express
express
    |---- express_test.js //运行主页
    |---- apiRouter.js // 路由模块文件

1、编写get 、post 方式接口

①、创建一个基本服务
②、创建API路由模块apiRouter.js并导出
③、编写 GET & POST 接口逻辑
④、导入路由模块

//apiRouter.js
//导入express、router
const express = require('express')
const router = express.Router()

//定义get方式请求  接口名为bookname
router.get('/bookname',(req,res)=>{
  //通过req.query获取get请求参数
  const query = req.query

  //向客户端响应处理结果
  res.send({
    status:200,//200表示成功 204表示失败
    msg:'GET请求成功',
    data:query,//返回给客户端的数据, 这里示例直接把客户端传过来的数据返回给用户
  })
})

//定义post方式请求 接口名为 shopname
router.post('/shopname',(req,res)=>{
  //通过req.body获取post请求参数
  const body = req.body

  //向客户端响应处理结果
  res.send({
    status:200,//200表示成功 204表示失败
    msg:'POST请求成功',
    data:body,//返回给客户端的数据
  })
})

//导出路由
module.exports = router
// express_test.js 
//express 编写接口
const express = require('express')
const app = express()


//========此端 是jsonp 接口例子 ============ 配置jsonp 接口  必须在cors之前调用 (jsonp 是get的)=====================
app.get('/api/jsonp',(req,res)=>{
    //接收客户端发送的回调函数名称
    const funcName = req.query.callback
    //要发送给客户端的数据
    const data = {name:'测试jsonp',age:18}
    //拼接一个完整的字符串
    const result = `${funcName}(${JSON.stringify(data)})`
    //将拼接好的字符串返回给客户端
    res.send(result)
})
//==================== 配置jsonp 接口  end =====================


//=========== 此两行是解决跨域问题的 =================
const cors = require('cors')

//配置解决跨域问题  注意:必须在注册路由之前调用
app.use(cors())
//============此两行是解决跨域问题的  end =============

//配置解析表单数据的中间件  记得放在注册路由之前 (post 时会用)
app.use(express.urlencoded({extended:false}))

//导入路由模块
const useRouter = require('./apiRouter')

//注册路由,并设置统一前缀,名为api
app.use('/api',useRouter)

app.listen(3000,()=>{
    console.log('服务器启动成功 http://127.0.0.1:3000')
})

启动服务(node express_test.js , 或者如果安装了nodemon工具 nodemon express_test.js),通过浏览器或者postman访问 http://127.0.0.1:3000/api/bookname?id=12&name=%E8%A5%BF%E6%B8%B8%E8%AE%B0&english=xiyouji&price=888

2、cors 解决跨域

和js同级新建一个index.html,接口用刚刚写好的试验会发现有跨域问题

解决接口跨域主要有两种:

1、CORS (主流的解决方案)

2、JSONP (有缺陷的解决方案:只支持 GET 请求)

cors 是 Express 的一个三方中间件,安装配置cors可解决跨域问题
①、npm i cors 安装中间件
②、const cors = require('cors') 导入中间件
③、在路由前导入配置中间件 app.use(cors())

 此时在运行html,点击按钮请求接口就可以成功返回数据

3、关于 cors

CORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源。

浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头就可以解除浏览器端的跨域访问限制。

注意:
①、CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口。
②、CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。

cors 响应头

Access-Control-Allow-Origin
//格式
//<origin> 参数的值指定了 允许访问该资源的外域URL                          
Access-Control-Allow-Origin:<origin> | *
//通配符 *,允许所有的域名访问
res.setHeader('Access-Control-Allow-0rigin','*')

//只允许 来自 https://test.com 域名下的访问
res.setHeader('Access-Control-Allow-0rigin','https://test.com')
Access-Control-Allow-Headers

默认情况下cors仅支持 客户端向服务器发送如下9个请求头:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、 Width、Content-Type ( 值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)


如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!
 

//允许客户端额外向服务器发送Content-Type 请求头和 X-Custom-Header 请求头
//注意:多个请求头之间使用英文的逗号进行分割
//如额外声明了 Content-Type 和 Custom-Header 两个请求头
res.setHeader('Access-Control-Allow-Headers','Content-Type,Custom-Header')
Access-Control-Allow-Methods

默认情况下,CORS 仅支持客户端发起 GET、POST、HEAD 请求。
如果客户端希望通过 PUT、DELETE等方式请求服务器的资源,则需要在服务器端,通过 Access-Control-Alow-Methods来指明实际请求所允许使用的 HTTP 方法。
 

//只允许 POST, GET, DELETE, HEAD 请求方法
res.setHeader('Access-Control-Allow-Methods','POST, GET, DELETE, HEAD')

//允许所有请求方法
res.setHeader('Access-Control-Allow-Methods','*')

cors请求分类

根据请求方式和请求头的不同可以分为2大类:简单请求 和 预检请求

简单请求(同时满足以下2点):
①、请求方式是GET、POST、HEAD三者之一
②、HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)

预检请求(符合以其中1点):
①、请求方式为GET、POST、HEAD之外的请求 Method类型
②、请求头中包含自定义头部字段
③、向服务器发送了 application/json 格式的数据

预检请求:在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这-次的 OPTION 请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

二者区别:

简单请求的特点:客户端与服务器之间只会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求。

预检请求示例

//在上面apiRouter.js 中添加如下代码
//定义delete方式请求
router.delete('/delete',(req,res)=>{
  //通过req.query获取get请求参数
  const query = req.query

  //向客户端响应处理结果
  res.send({
    status:200,//200表示成功 204表示失败
    msg:'DELETE请求成功',
    data:query,//返回给客户端的数据
  })
})
//html 中添加如下测试代码
<div class="post" onclick="delet()">请求delet接口测试</div>

function delet(){
  $.ajax({
    type:"delete",
    url:"http://127.0.0.1:3000/api/delete?id=12",
    success:function(data){
      console.log('delete接口请求返回',data);
    }
  })
}

启动服务,分别点击按钮,查看控制台中的网络,点击get或者post按钮都只有1次,但是delete 会有2次

4、JSONP

浏览器端通过 <script>标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP。
JSONP特点:
① JSONP 不属于真正的 Ajax 请求,因为它没有使用 XMLHttpRequest 这个对象
② JSONP 仅支持 GET 请求,不支持 POST、PUT、DELETE 等请求

注意:如果项目中已经配置了 CORS 跨域资源共享,为了防止冲突,必须在配置 CORS 中间件之前声明 JSONP 的接口。否则JSONP 接口会被处理成开启了CORS的接口。

 //优先创建 JSONP 接口
 app.get('/api/jsonp',(req,res)=>{ }) //这个接口不会被处理成 CORS 接口

// 再配置CORS中间件
//这个后面的所有接口,都会被处理成 CORS 接口
app.use(cors())

app.get('/api/get',(req,res)=>{})//比如这个就是开启了CORS 的接口
//express_test.js
//jsonp接口 
//具体代码在 五 中第1小节代码中有标注
//html 中继续添加
<div class="post" onclick="jsonp()">请求jsonp接口测试</div>

function jsonp(){
  $.ajax({
    type:"get",
    url:"http://127.0.0.1:3000/api/jsonp",
    dataType:"jsonp",
    success:function(data){
      console.log('jsonp接口请求返回',data);
    }
  })
}

5、express中使用session

Cookie 是存储在用户浏览器中的一段不超过4KB 的字符串。它由一个名称(Name)、一个值(Value)和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。

不同域名下的 Cookie 各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的 Cookie 一同发送到服务器

Cookie特性:自动发送、域名独立、过期时限、4KB限制、不具安全性express提供三方中间件 express-session

npm i express-session //安装

引入并注册,具体使用字段可查询官网说明:https://www.npmjs.com/package/express-session

//express_test.js
//继续在 express_test.js 文件中导入session并全局注册
const session = require('express-session')
app.use(session({
        secret:'keyboard cat',
        resave:false,
        saveUninitialized:true
    })
)

6、express中使用 JWT生成token

安装jsonwebtoken、express-jwt

jsonwebtoken 用于生成 JWT 字符串
express-jwt 用于将 JWT 字符串解析还原成 JSON 对象

npm install jsonwebtoken express-jwt

我这里遇到一个问题 安装完express-jwt后下面引用时一直报错  expressJWT is not a function  默认安的8+版本,按照官网的方式修改引入也报错,后来降低版本可以

项目中导入包

//express_test.js
const jwt = require('jsonwebtoken') //导入生成jwt字符串的包
const expressJWT = require('express-jwt')//解析由jwt生成字符串的包

const secretKey = 'test password' //定义一个秘钥,值是一个字符串

定义secret秘钥

了保证 JWT 字符串的安全性,防止 JWT 字符串在网络传输过程中被别人破解,定义一个用于加密和解密的 secret 密钥:
① 当生成 JWT 字符串的时候,需要使用 secret 密钥对用户的信息进行加密,最终得到加密好的JWT 字符串

② 当把 JWT 字符串解析还原成 JSON 对象的时候,需要使用 secret 密钥进行解密

 写一个登录和用户信息接口

//express_test.js
const express = require('express')
const app = express()
const cors = require('cors')//解决跨域
const session = require('express-session')//保存session

const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
const secretKey = 'test password' //定义一个秘钥,值是一个字符串


//配置解决跨域问题  注意:必须在注册路由之前调用
app.use(cors())

//配置解析表单数据的中间件  记得放在注册路由之前
app.use(express.urlencoded({extended:false}))
//unless 指定带有api的接口不需要访问权限
app.use(expressJWT({secret:secretKey}).unless({ path: [/^\/api\//] }) ) //注册解密token的中间件

//注册 session 全局中间件
app.use(session({
    secret:secretKey,
    resave:false,
    saveUninitialized:true
}) )


//登录接口
app.post('/api/login',(req,res)=>{
    if(req.body.username === 'admin' && req.body.password === '123456'){
      const userInfo = req.body
      req.session.userInfo =userInfo
      req.session.isLogin = true
     //expiresIn 设置token有效时间
      const token = jwt.sign({username:userInfo.name},secretKey,{expiresIn:'50s'}) //对用户信息进行加密
  
      res.send({
        status:200,
        msg:'登录成功',
        data:{
          token:token,
          ...req.body,
        }
      })
    }else{
      res.send({
        status:204,
        msg:'用户名或密码错误',
        data:req.body
      })
    }
  
})
//获取用户信息接口
app.post('/user',(req,res)=>{
    if(req.session.isLogin){
      res.send({
        status:200,
        msg:'获取用户信息成功',
        data:req.session.userInfo
      })
    }else{
      res.send({
        status:204,
        msg:'获取用户信息失败',
        data:req.session.userInfo
      })
    }
})

//
app.listen(3000,()=>{
    console.log('服务器启动成功: http://127.0.0.1:3000')
})

注意:获取用信息时,请求头的key是 authorization  值 一定要加上 Bearer 空格后加上token


http://www.kler.cn/news/303859.html

相关文章:

  • 鸿蒙(API 12 Beta6版)GPU加速引擎服务【自适应VRS】
  • C语言 条件编译
  • 【2024】前端学习笔记5-表单标签使用
  • leaflet【十】实时增加轨迹点轨迹回放效果实现
  • 2024/9/11学校教的响应式前端能学到什么?
  • 【路径规划】APF算法、Vortex APF算法、Safe APF算法和动态Windows方法的比较
  • AI教你学Python 第3天:函数和模块
  • ai智能语电销机器人有哪些功能?
  • 初识软件测试
  • 数据结构——单链表基本操作的实现
  • 我与Linux的爱恋:自动化构建工具-make/Makefile
  • 测试-Gatling 与性能测试
  • 98、RS485全自动收发电路入坑笔记
  • Gmtracker_深度学习驱动的图匹配多目标跟踪项目启动与算法流程
  • ES机制原理
  • linux ubuntu编译 openjdk11
  • 中国科技统计年鉴1991-2020年
  • JDBC客户端连接Starrocks 2.5
  • python-回文数(一)
  • 4G MQTT网关在物联网应用中的优势-天拓四方
  • 组播 2024 9 11
  • 为什么mac打不开rar文件 苹果电脑打不开rar压缩文件怎么办
  • 基于Java-SpringBoot+vue实现的前后端分离信息管理系统设计和实现
  • element实现动态路由+面包屑
  • Vue的学习(三)
  • vue2响应式系统是如何实现的(手写)
  • 代码随想录刷题day32丨动态规划理论基础,509. 斐波那契数, 70. 爬楼梯, 746. 使用最小花费爬楼梯
  • 基于Python实现一个庆祝国庆节的小程序
  • Kubernetes 与 springboot集成
  • 【九盾安防】叉车使用安全新升级!指纹识别锁,验证司机操作权限