Node.js知识点总结

Node.js知识点总结

Node.js其本质和浏览器一样是一个JavaScript运行环境。浏览器的运行环境为V8引擎+浏览器内置API(BOM、DOM、Canvas);而node.js的运行环境是V8引擎+node提供的API(fs、path、http)。它使JavaScript可以编写后端。

基本知识

fs文件系统模块

  • 它提供一系列的方法和属性,用来满足用户对文件的操作需求

  • 使用语法:

  • 加载 fs 模块,得到 fs 对象

js 复制代码
const fs = require('fs')
  • 写入文件内容语法:
js 复制代码
fs.writeFile('文件路径', '写入内容', err => {
  // 写入后的回调函数
})
  • 读取文件内容的语法:
js 复制代码
fs.readFile('文件路径', (err, data) => {
  // 读取后的回调函数
  // data 是文件内容的 Buffer 数据流
})
  • 需求:向 test.txt 文件写入内容并读取打印
html 复制代码
/**
 * 目标:使用 fs 模块,读写文件内容
 * 语法:
 * 1. 引入 fs 模块
 * 2. 调用 writeFile 写入内容
 * 3. 调用 readFile  读取内容
 */
// 1.加载fs模块对象
const fs = require('fs')
// 2.写入文件内容
fs.writeFile('./test.txt', 'hello,Node.js', (err) => {
  if(err) console.log(err)
    else console.log('写入成功')
})
// 3.读取文件内容
fs.readFile('./test.txt', (err, data) => {
  if (err) console.log(err)
    // data是buffer16进制数据流对象
    // toString()转换成字符串
    //<Buffer 68 65 6c 6c 6f 2c 4e 6f 64 65 2e 6a 73>
  else console.log(data.toString())
})

path路径模块

  • 它是用来处理路径的模块
  • 使用语法:
  • 加载 path 模块,得到 path对象
html 复制代码
const path = require('path')
  • 将多个路径片段拼接成一个完整路径字符串
html 复制代码
const path = require('path')
const fs = require('fs')

// 注意:  ../ 会抵消前面的路径
// const pathStr = path.join('/a', '/b/c', '../../', './d', 'e')
// console.log(pathStr)  // \a\b\d\e

// fs.readFile(__dirname + '/files/1.txt')

fs.readFile(path.join(__dirname, './files/1.txt'), 'utf8', function(err, dataStr) {
  if (err) {
    return console.log(err.message)
  }
  console.log(dataStr)
})
  • 从路径字符串中,将文件名解析出来
html 复制代码
const path = require('path')

// 定义文件的存放路径
const fpath = '/a/b/c/index.html'

// const fullName = path.basename(fpath)
// console.log(fullName)

const nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt) //输出index
  • 获取路径中的扩展名部分
html 复制代码
const path = require('path')

// 这是文件的存放路径
const fpath = '/a/b/c/index.html'

const fext = path.extname(fpath)
console.log(fext)//输出.html

http 模块

是用来创建 web 服务器的模块,通过 http模块提供的http.createServer() 方法,就能方便的把一台普通的电脑,变成一台Web服务器,从而提供资源服务

  • 基本语法:
html 复制代码
// 1. 导入 http 模块
const http = require('http')
// 2. 创建 web 服务器实例
const server = http.createServer()
// 3. 为服务器实例绑定 request 事件,监听客户端的请求
server.on('request', function (req, res) {
  console.log('Someone visit our web server.')
})
// 4. 启动服务器
server.listen(8080, function () {  
  console.log('server running at http://127.0.0.1:8080')
})
URL端口号
  • 是标记服务器里对应的服务程序,值为(0-65535 之间的任意整数
  • http 协议,默认访问的是 80 端口
req、res
  • req:是请求对象,包含了与客户端相关的数据和属性
  • res:是响应对象,包含了与服务器相关的数据和属性
html 复制代码
const http = require('http')
const server = http.createServer()
// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res) => {
  // req.url 是客户端请求的 URL 地址
  const url = req.url
  // req.method 是客户端请求的 method 类型
  const method = req.method
  const str = `Your request url is ${url}, and request method is ${method}`
  console.log(str)
  // 调用 res.end() 方法,向客户端响应一些内容
  res.end(str)
})
server.listen(80, () => {
  console.log('server running at http://127.0.0.1')
})

模块化

CommonJS 标准

Node.js中每一个文件都是一个独立的模块,项目由多个模块组成

由于各个模块的属性和函数是私有的,如果对外使用,则需要标准语法导入、导出,即 CommonJS 标准

  • 导出语法:
html 复制代码
module.exports = {
  对外属性名: 模块内私有变量
}
  • 导入语法:
html 复制代码
const 变量名 = require('模块名或路径')
// Node.js 环境内置模块直接写模块名(例如:fs,path,http)
// 自定义模块:写模块文件路径(例如:./utils.js)
  • 代码实现:

  • 导出

html 复制代码
/**
 * 目标:基于 CommonJS 标准语法,封装属性和方法并导出
 */
const baseURL = 'http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)

// 导出
module.exports = {
  url: baseURL,
  arraySum: getArraySum
}
  • 导入
html 复制代码
/**
 * 目标:基于 CommonJS 标准语法,导入工具属性和方法使用
 */
// 导入
const obj = require('./utils.js')
console.log(obj)
const result = obj.arraySum([5, 1, 2, 3])
console.log(result)

ECMAScript标准-默认导出和导入

  • CommonJS 规范为 Node.js 环境中默认的,后来官方推出 ECMAScript 标准语法

  • 注意:Node.js 默认只支持 CommonJS 标准语法,如果想要在当前项目环境下使用 ECMAScript 标准语法,请新建 package.json 文件设置 type: 'module' 来进行设置

html 复制代码
{ "type": "module" }
  • 导出语法:
js 复制代码
export default {
  对外属性名: 模块内私有变量
}
  • 导入语法:
js 复制代码
import 变量名 from '模块名或路径'
  • 语法实现:

  • 导出:

html 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,封装属性和方法并"默认"导出
 */
const baseURL = 'http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)

// 默认导出
export default {
  url: baseURL,
  arraySum: getArraySum
}
  • 导入:
html 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,"默认"导入,工具属性和方法使用
 */
// 默认导入
import obj from './utils.js'
console.log(obj)
const result = obj.arraySum([10, 20, 30])
console.log(result)

ECMAScript标准-命名导出和导入

  • 命名导出语法:
js 复制代码
export 修饰定义语句
  • 命名导入语法:
js 复制代码
import { 同名变量 } from '模块名或路径'
  • 语法实现:

  • utils.js 导出

js 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,封装属性和方法并"命名"导出
 */
export const baseURL = 'http://hmajax.itheima.net'
export const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)
  • index.js 导入
js 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,"命名"导入,工具属性和方法使用
 */
// 命名导入
import {baseURL, getArraySum} from './utils.js'
console.log(obj)
console.log(baseURL)
console.log(getArraySum)
const result = getArraySum([10, 21, 33])
console.log(result)

npm包

  • 将模块,代码,其他资料整合成一个文件夹,这个文件夹就叫包

  • 包分类:

项目包:主要用于编写项目和业务逻辑

软件包:封装工具和方法进行使用

包管理工具

  • 初始化清单文件: npm init -y
  • 下载软件包:npm i 软件包名称
  • 使用软件包
html 复制代码
/**
 * 目标:使用 npm 下载 dayjs 软件包来格式化日期时间
 *  1. (可选)初始化项目清单文件,命令:npm init -y
 *  2. 下载软件包到当前项目,命令:npm i 软件包名称
 *  3. 使用软件包
 */
// 3. 使用软件包
const dayjs = require('dayjs')
const nowDateStr = dayjs().format('YYYY-MM-DD')
console.log(nowDateStr)
  • 使用流程图:

npm全局软件包-nodemon

  1. 本地软件包:只在当前项目内使用,存在于 node_modules
  2. 全局软件包:本机所有项目使用,存在于系统设置的位置
  3. nodemon 作用:替代 node 命令,检测代码更改,自动重启程序
  4. 使用:
  • 安装:npm i nodemon -g (-g 代表安装到全局环境中)
  • 运行:nodemon 待执行的目标 js 文件

express

基本知识

  • 就是一个 npm上的第三方包,提供了快速创建Web服务器的便捷方法
  • 相较于http,express是基于内置的 http模块进一步封装出来的,开发效率更高

1.安装:

html 复制代码
npm i express@4.17.1

2.创建基本的Web 服务器

3...监听 GET 、POST请求

4.把内容响应给客户端 res.send()

5.获取URL 中携带的查询参数:通过 req.query 对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数

6.获取URL 中的动态参数:通过 req.params 对象,可以访问到URL中,通过:匹配到的动态参数

html 复制代码
// 1. 导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()

// 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象
  res.send({ name: 'zs', age: 20, gender: '男' })
})
app.post('/user', (req, res) => {
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串
  res.send('请求成功')
})
app.get('/', (req, res) => {
  // 通过 req.query 可以获取到客户端发送过来的 查询参数
  // 注意:默认情况下,req.query 是一个空对象
  console.log(req.query)
  res.send(req.query)
})
// 注意:这里的 :id 是一个动态的参数
app.get('/user/:ids/:username', (req, res) => {
  // req.params 是动态匹配到的 URL 参数,默认也是一个空对象
  console.log(req.params)
  res.send(req.params)
})

// 3. 启动 web 服务器
app.listen(80, () => {
  console.log('express server running at http://127.0.0.1')
})

express路由

  • 在 Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系
  • 由3 部分组成,分别是请求的类型、请求的 URL 地址、处理函数

1.路由匹配过程:

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

用法:

1)创建路由模块对应的 .js文件

2)调用 express.Router()函数创建路由对象

3)向路由对象上挂载具体的路由

4)使用 module.exports 向外共享路由对象

html 复制代码
var express = require('express')     //1.导入express
var router = express.Router()        //2.创建路由对象

router.get('/user/list', function (req,res) {  //3.挂载获取用户列表的路由
res.send('Get user list')
})
router.post('/user/add', function (req,res) {  //4.挂载添加用户的路由
res.send('Add new user')
})

moudle.export = router                          //5.向外导出路由对象

5)使用app.use()函数注册路由模块

html 复制代码
//1.导入路由模块
const userRouter = require('./router/user.js')
//2.使用app.use()注册路由模块,并添加统一的访问前缀 /api
app.use('/api',userRouter)

express中间件

  • 当一个请求到达 Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
html 复制代码
//包含 req, res, next 三个参数,next() 参数把流转关系交给下一个中间件或路由
const mw = function(req, res, next){
	next()
}
html 复制代码
const express = require('express')
const app = express()

// // 定义一个最简单的中间件函数
// const mw = function (req, res, next) {
//   console.log('这是最简单的中间件函数')
//   // 把流转关系,转交给下一个中间件或路由
//   next()
// }

// // 将 mw 注册为全局生效的中间件
// app.use(mw)

// 这是定义全局中间件的简化形式
app.use((req, res, next) => {
  console.log('这是最简单的中间件函数')
  next()
})

app.get('/', (req, res) => {
  console.log('调用了 / 这个路由')
  res.send('Home page.')
})
app.get('/user', (req, res) => {
  console.log('调用了 /user 这个路由')
  res.send('User page.')
})

app.listen(80, () => {
  console.log('http://127.0.0.1')
})

使用express写接口

html 复制代码
// 导入 express
const express = require('express')
// 创建服务器实例
const app = express()

// 配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false }))

// 必须在配置 cors 中间件之前,配置 JSONP 的接口
app.get('/api/jsonp', (req, res) => {
  // TODO: 定义 JSONP 接口具体的实现过程
  // 1. 得到函数的名称
  const funcName = req.query.callback
  // 2. 定义要发送到客户端的数据对象
  const data = { name: 'zs', age: 22 }
  // 3. 拼接出一个函数的调用
  const scriptStr = `${funcName}(${JSON.stringify(data)})`
  // 4. 把拼接的字符串,响应给客户端
  res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require('cors')
app.use(cors())

// 导入路由模块
const router = require('./16.apiRouter')
// 把路由模块,注册到 app 上
app.use('/api', router)

// 启动服务器
app.listen(80, () => {
  console.log('express server running at http://127.0.0.1')
})

数据库

  • 数据库(database)是用来组织、存储和管理数据的仓库
  • MySQL是目前使用最广泛、流行度最高的开源免费数据库
  • SQL 是一门数据库编程语言,能够让我们以编程的形式,操作数据库里面的数据。

基本操作

1.连接数据库

2.了解主界面组成部分

3.创建数据库

4.创建数据表

5.向表中写入数据

使用SQL管理数据库

  • 掌握使用SQL从数据表中:查询数据(select)、插入数据(insertinto)、更新数据(update)、删除数据(delete)
html 复制代码
//获取数据表
select * from users

//从user表中获取username和password的内容
select username, password from user
  • 插入数据
  • update修改数据

把 users表中id为7的用户密码,更新为888888

  • 删除数据

从 users表中,删除id 为4的用户,示例如下

  • where语句
html 复制代码
//1.查询status为1的所有用户
SELECT * FROM use  WHERE status=1
//2.查询id大于4的所有用户
OM use  WHERE status>4

在项目中操作MySQL

1.安装 mysql 模块

html 复制代码
npm i mysql

2.配置mysql

html 复制代码
const mysql = require('mysql')

const db = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: 'root',
    database: 'test',
})

3.检测是否能正常工作

html 复制代码
db.query('select 1', (err, results) => {
   if (err) return console.log(err.message)
   console.log(results)
})

4.使用 mysql 模块操作 MySQL 数据库

  • 查询数据
html 复制代码
// 查询 users 表中所有的数据
/* const sqlStr = 'select * from users'
db.query(sqlStr, (err, results) => {
  // 查询数据失败
  if (err) return console.log(err.message)
  // 查询数据成功
  // 注意:如果执行的是 select 查询语句,则执行的结果是数组
  console.log(results)
}) */
  • 插入数据
html 复制代码
// 向 users 表中,新增一条数据,其中 username 的值为 Spider-Man,password 的值为 pcc123
/* const user = { username: 'Spider-Man', password: 'pcc123' }
// 定义待执行的 SQL 语句
const sqlStr = 'insert into users (username, password) values (?, ?)'
// 执行 SQL 语句
db.query(sqlStr, [user.username, user.password], (err, results) => {
  // 执行 SQL 语句失败了
  if (err) return console.log(err.message)
  // 成功了
  // 注意:如果执行的是 insert into 插入语句,则 results 是一个对象
  // 可以通过 affectedRows 属性,来判断是否插入数据成功
  if (results.affectedRows === 1) {
    console.log('插入数据成功!')
  }
}) */
------------------------------------------------------------------
//插入数据便捷方式
/* const user = { username: 'Spider-Man2', password: 'pcc4321' }
// 定义待执行的 SQL 语句
const sqlStr = 'insert into users set ?'
// 执行 SQL 语句
db.query(sqlStr, user, (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('插入数据成功')
  }
}) */
  • 更新数据
html 复制代码
// 演示如何更新用户的信息
/* const user = { id: 6, username: 'aaa', password: '000' }
// 定义 SQL 语句
const sqlStr = 'update users set username=?, password=? where id=?'
// 执行 SQL 语句
db.query(sqlStr, [user.username, user.password, user.id], (err, results) => {
  if (err) return console.log(err.message)
  // 注意:执行了 update 语句之后,执行的结果,也是一个对象,可以通过 affectedRows 判断是否更新成功
  if (results.affectedRows === 1) {
    console.log('更新成功')
  }
}) */
-----------------------------------------------------------------------------
// 演示更新数据的便捷方式
/* const user = { id: 6, username: 'aaaa', password: '0000' }
// 定义 SQL 语句
const sqlStr = 'update users set ? where id=?'
// 执行 SQL 语句
db.query(sqlStr, [user, user.id], (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('更新数据成功')
  }
}) */
  • 删除数据:
html 复制代码
const sql = 'delete from users where id=?'
//4代表user.id
//若SQL语句中有多个占位符,则必须使用数组为每个占位符指定具体的值
//若SQL语句中只有一个占位符,则可以省略
db.query(sql, 4, (err, results) => {
  	if (err) return console.log(err.message)
    if (results.affectedRows === 1) console.log('删除数据成功')
})
  • 标记删除:

由于使用 delete 语句会真正删除数据,保险起见,使用标记删除的形式,模拟删除的动作。即在表中设置状态status字段,标记当前的数据是否被删除

html 复制代码
const sqlStr = 'update users set status=? where id=?'
db.query(sqlStr, [1, 6], (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('标记删除成功')
  }
})

前后端的身份认证

Web开发模式

目前主流的有两类:基于服务端渲染 的传统Web开发模式、基于前后端分离的新型Web开发模式

1)服务端渲染的传统Web开发模式:服务器发送给客户端的 HTML 页面,是在服务器通过字符串的拼接动态生成的→客户端不需要使用 Ajax 额外请求页面的数据

利:前端耗时短;有利于SEO

缺点:占用服务器资源;不利于前后的分离

html 复制代码
app.get('/index.html', (req, res) => {
//1.要渲染的数据
  const user = { name: 'Bruce', age: 29 }
//2.服务器端通过字符串的拼接,动态生成HTML内容
  const html = `<h1>username:${user.name}, age:${user.age}</h1>`
//3.把生成好的页面内容响应给客户端→故客户端拿到的是带有真实数据的HTML页面
  res.send(html)
})

2)前后端分离的 Web 开发模式:即后端只负责提供API 接口,前端使用 Ajax 调用接口的开发模式

  • 利:前端专注页面开发,后端专注接口开发;页面局部刷新,无需重新请求页面
  • 不利:不利于 SEO。完整的 HTML 页面在浏览器拼接完成,因此爬虫无法爬取页面的有效信息。→利用Vue、React等前端框架的SSR(serverside render)技术能够很好的解决SEO问题

3)应用场景:

  • 企业级网站,主要功能为展示,无复杂交互且需要良好的SEO,故采用服务器端渲染;
  • 后台管理项目,交互性较强,不需要考虑SEO→前后端分离的 Web 开发模式

身份认证

  • 身份认证又称为鉴权,通过一定的手段,完成对用户身份的确认。
  • 服务端渲染推荐使用session认证机制;前后端分离推荐使用JWT认证机制
session认证机制
  • 工作原理:

  • 安装express-session中间件

html 复制代码
npm install express-session
  • 配置中间件:需要通过 app.use()来注册 session 中间件
html 复制代码
const session = require('express-session')
app.use(
	session({
		secret: '做一只猫', 		// secret 属性的值为任意字符串
		resave: false,			//固定写法
		saveUninitalized: true	//固定写法
  })
)
  • 向sessin中存数据:通过req.session访问session对象,存储用户信息
html 复制代码
app.post('/api/login', (req, res) => {
	//判断用户提交的登录信息是否正确
	if(req.body.username !== 'admin' || req.body.password !== '000000'){
		return res.send({status: 1, msg: '登录失败'})
	}
	req.session.user = req.body	//将用户的信息存储到S
	req.session.isLogin = true

 	res.send({ status: 0, msg: 'login done' })
})
  • 从session中取数据
html 复制代码
app.get('/api/username', (req, res) => {
	//判断用户是否登录
 	if (!req.session.isLogin) {
    	return res.send({ status: 1, msg: 'fail' })
  	}
  	res.send({ status: 0, msg: 'success', username: req.session.user.username })
})
  • 清空数据
html 复制代码
app.post('/api/logout', (req, res) => {
 	// 清空当前客户端的session信息
	req.session.destroy()
	res.send({ status: 0, msg: '退出登录成功' })
})
  • 局限性:Session 认证机制需要配合 Cookie 才能实现。由于Cookie默认不支持跨域访问→当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域 Session认证
JWT认证机制
  • 当前端需要跨域请求后端接口的时候,推荐使用JWT认证机制

  • 工作原理:

  • JWT组成部分:Header(头部)、Payload(有效荷载)、Signature(签名),三者使用.分隔

  • 使用方法:把 JWT 放在 HTTP 请求头的 Authorization 字段中

html 复制代码
Authorization: Bearer <token>

Express 使用 JWT

1)安装JWT相关的包

ljsonwebtoken 用于生成 JWT 字符串

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

html 复制代码
//安装多个包中间用空格隔开
npm install jsonwebtoken express-jwt

2)导入 JWT 相关的包:使用 require() 函数,分别导入 JWT相关的两个包

html 复制代码
//1.导入用于生成字符串的包
const jwt = require('jsonwebtoken')
//2.导入用于将客户端发送过来的IWT字符串,解析还原称JSON对象的包
const expressJWT = require('express-jwt')

3)定义secret 密钥:

为保证 JWT 字符串安全性,需定义一个用于加密和解密的secret密钥

html 复制代码
/ 密钥可以为任意字符串
const secretKey = 'dimple'

4)在登录成功后生成 JWT 字符串

调用 jsonwebtoken 包提供的sign()方法,将用户的信息加密成JWT字符串,响应给客户端

html 复制代码
app.post('/api/login', (req, res) => {
 //用户登录成功后,生成JWT字符串,通过token属性响应给客户端
  res.send({
    status: 200,
    message: '登录成功',
    // 调用jwt.sign() 生成 JWT 字符串,三个参数分别是用户信息对象,加密密钥,配置对象
    token: jwt.sign({username: userInfo.username}, secretKey, {expiresIn: '30s'})
  })
})

5)将JWT 字符串还原为 JSON 对象

html 复制代码
// unless({ path: [/^\/api\//] }) 指定哪些接口无需访问权限
app.use(expressJWT({ 
	secret: secretKey
}).unless({ path: [/^\/api\//] }))

6)使用req.user 获取用户信息

html 复制代码
app.get('/admin/getinfo', (req, res) => {
  console.log(req.user)
  res.send({
    status: 200,
    message: '获取信息成功',
    //data: req.user
    //6.0版本后改用req.auth
    data: req.auth
  })
})

7)捕获解析JWT 失败后产生的错误

html 复制代码
app.use((err, req, res, next) => {
//token解析失败导致的错误
  if (err.name === 'UnauthorizedError') {
    return res.send({ status: 401, message: 'Invalid token' })
  }
//其它原因导致的错误
  res.send({ status: 500, message: 'Unknown error' })
})
相关推荐
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端
爱敲代码的小鱼9 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax