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

wap网站编辑器目录在标题后 wordpress

wap网站编辑器,目录在标题后 wordpress,最近的电脑培训学校,美工自学网KOA 介绍 官网地址#xff1a; https://koa.bootcss.com/ Koa 是一个新的 web 框架#xff0c;由 Express 幕后的原班人马打造#xff0c; 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数#xff0c;Koa 帮你丢弃回调… KOA 介绍 官网地址 https://koa.bootcss.com/ Koa 是一个新的 web 框架由 Express 幕后的原班人马打造 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数Koa 帮你丢弃回调函数并有力地增强错误处理。 Koa 并没有捆绑任何中间件 而是提供了一套优雅的方法帮助您快速而愉快地编写服务端应用程序。 文章目录 KOA 介绍一. 项目的初始化1 npm 初始化2 git 初始化 二. 搭建项目1 安装 Koa 框架2 编写最基本的 app3 测试 三. 项目的基本优化1 自动重启服务2 读取配置文件3 洋葱模型 四. 添加路由1 安装 koa-router2 编写路由3 改写 main.js4.ctx对象 五. 目录结构优化1 将 http 服务和 app 业务拆分2 将路由和控制器拆分 六. 解析 body1 安装 koa-body2 注册中间件3 解析请求数据4 拆分 service 层5 洋葱模型 七. 集成 sequlize1 安装 sequelize2 连接数据库3 编写配置文件 八. 创建 User 模型1 拆分 Model 层 九. 添加用户入库十. 错误处理十一. 拆分中间件1 拆分中间件2 统一错误处理3 错误处理函数 十二. 加密1 安装 bcryptjs2 编写加密中间件3 在 router 中使用 十三. 登录验证十四. 用户的认证1 颁发 token1) 安装 jsonwebtoken2) 在控制器中改写 login 方法3) 定义私钥 2 用户认证1) 创建 auth 中间件2) 改写 router 十五 接口练习十六 koa集成 模板引擎EJS 的使用art-template 一. 项目的初始化 1 npm 初始化 npm init -y生成package.json文件: 记录项目的依赖 2 git 初始化 git init生成’.git’隐藏文件夹, git 的本地仓库 二. 搭建项目 1 安装 Koa 框架 npm install koa2 编写最基本的 app 创建src/main.js const Koa require(koa)const app new Koa()app.use((ctx, next) {ctx.body hello world })app.listen(3000, () {console.log(server is running on http://localhost:3000) })3 测试 在终端, 使用node src/main.js 三. 项目的基本优化 1 自动重启服务 安装 nodemon 工具 npm i nodemon -D编写package.json脚本 scripts: {dev: nodemon ./src/main.js,test: echo \Error: no test specified\ exit 1 },执行npm run dev启动服务 2 读取配置文件 安装dotenv, 读取根目录中的.env文件, 将配置写到process.env中 npm i dotenv创建.env文件 APP_PORT8000创建src/config/config.default.js const dotenv require(dotenv)dotenv.config()// console.log(process.env.APP_PORT)module.exports process.env改写main.js const Koa require(koa)const { APP_PORT } require(./config/config.default)const app new Koa()app.use((ctx, next) {ctx.body hello api })app.listen(APP_PORT, () {console.log(server is running on http://localhost:${APP_PORT}) })3 洋葱模型 洋葱模型就是将数据顺序传入到多个中间件中让它们进行处理传递并利用函数递归的特性让我们可以在一个中间件内先执行前半部分逻辑再执行之后的所有中间件的完整逻辑后再掉转方向继续执行这个中间件的后半部分。 const Koa require(koa); const app new Koa();// 中间件1 app.use((ctx, next) {console.log(1);next();console.log(1); });// 中间件 2 app.use((ctx, next) {console.log(2);next();console.log(2); });// 中间件 3 app.use((ctx, next) {console.log(3);next();console.log(3); }); app.listen(8000, 0.0.0.0, () {console.log(Server is starting); });在 koa 中中间件被 next() 方法分成了两部分。next() 方法上面部分会先执行下面部门会在后续中间件执行全部结束之后再执行。可以通过下图直观看出 输出的结果 1 2 3 3 2 1const Koa require(koa); const app new Koa();// 中间件1 app.use(async(ctx, next) {console.log(1);await next();console.log(1); });// 中间件 2 app.use(async(ctx, next) {console.log(2);const axios require(axios) const res await axios.get(http://www.baidu.com)next();console.log(2); });// 中间件 3 app.use((ctx, next) {console.log(3);next();console.log(3); }); app.listen(8000, 0.0.0.0, () {console.log(Server is starting); });四. 添加路由 路由: 根据不同的 URL, 调用对应处理函数 1 安装 koa-router npm i koa-router步骤: 导入包实例化对象编写路由注册中间件 2 编写路由 创建src/router目录, 编写user.route.js const Router require(koa-router)const router new Router({ prefix: /users })// GET /users/ router.get(/, (ctx, next) {ctx.body hello users })module.exports router3 改写 main.js const Koa require(koa)const { APP_PORT } require(./config/config.default)const userRouter require(./router/user.route)const app new Koa()app.use(userRouter.routes())app.listen(APP_PORT, () {console.log(server is running on http://localhost:${APP_PORT}) })mock 返回 router.get(/api/data, async (ctx) {// 查询成功返回数据const data {message: 查询成功,value: xx数据,};ctx.body data; });router.post(/api/data, async (ctx) {// 创建数据成功const data {message: 创建成功,value: xx数据,};ctx.body data; });router.put(/api/data, async (ctx) {// 修改成功const data {message: 修改成功,value: xx数据,};ctx.body data; });router.delete(/api/data, async (ctx) {// 删除成功const data {message: 删除成功,value: xx数据,};ctx.body data; });链式调用 router.get(/api/data, async (ctx) {ctx.body {message: 查询成功,value: xx数据,};}).post(/api/data, async (ctx) {ctx.body {message: 创建成功,value: xx数据,};}).put(/api/data, async (ctx) {ctx.body {message: 修改成功,value: xx数据,};}).delete(/api/data, async (ctx) {ctx.body {message: 删除成功,value: xx数据,};});// 定义处理数据的函数 const handleData (ctx, method, message) {const data {message,value: xx数据,};ctx.body data; };// 定义路由处理 router.get(/api/data, async (ctx) {handleData(ctx, 查询成功, xx数据);}).post(/api/data, async (ctx) {handleData(ctx, 创建成功, xx数据);}).put(/api/data, async (ctx) {handleData(ctx, 修改成功, xx数据);}).delete(/api/data, async (ctx) {handleData(ctx, 删除成功, xx数据);});4.ctx对象 在 Koa 框架中ctx 是 context 的简写。context 是 Koa 内部提供的一个全局变量它是一个带有请求和响应信息的上下文对象。ctx 对象封装了 context提供了访问请求和响应的属性和方法的方便方式。 通过 ctx 对象你可以访问 ctx.request、ctx.response、ctx.cookies 等属性来处理请求、响应和操作 cookie 数据。例如ctx.request.query 用于获取查询参数ctx.response.body 用于设置响应体内容ctx.cookies.set() 用于设置 cookie 数据等。 因此可以将 ctx 理解为上下文对象 context 的实例化对象它提供了更简洁和易用的方式来访问和操作请求和响应的相关信息。通过使用 ctx你可以在 Koa 应用程序的中间件中轻松地处理和操作请求和响应的数据。 ctx.request用于处理请求相关的属性和方法。 router.get(/api/data, async (ctx) {// 获取请求参数const queryParam ctx.request.query; // 获取查询参数const bodyParam ctx.request.body; // 获取请求体参数// 设置响应状态码ctx.response.status 200;// 设置响应类型ctx.response.type application/json;// 设置响应头ctx.response.set(X-Custom-Header, Custom Value);// 发送响应ctx.response.body { message: 请求成功 }; });ctx.response用于处理响应相关的属性和方法。 router.post(/api/data, async (ctx, next) {// 获取请求体参数const bodyParam ctx.request.body;// 设置响应状态码ctx.response.status 201;// 设置响应类型ctx.response.type application/json;// 设置响应头ctx.response.set(X-Custom-Header, Custom Value);// 发送响应ctx.response.body { message: 创建成功, data: bodyParam };await next(); });ctx.cookies用于操作 cookie。 router.get(/api/cookie, async (ctx) {// 设置 cookiectx.cookies.set(name, value, {httpOnly: true,maxAge: 86400000, // 设置过期时间为一天});// 获取 cookieconst name ctx.cookies.get(name);ctx.body { cookie: name }; });通过这些属性你可以方便地处理请求的参数、设置响应的状态码、类型、头部信息以及操作 cookie 数据。以上是一些简单的示例实际使用中可能还会涉及更多的属性和方法具体的使用取决于你的业务需求。 const Koa require(koa); const bodyParser require(koa-bodyparser);const app new Koa(); app.use(bodyParser());app.use(async (ctx) {if (ctx.url /api/data ctx.method POST) {const bodyData ctx.request.body;console.log(bodyData); // 获取请求体数据ctx.body { message: 请求成功, data: bodyData };} });app.listen(3000, () {console.log(服务器启动监听3000端口...); });ctx.response.bodyctx.body 本质上是一个东西 五. 目录结构优化 1 将 http 服务和 app 业务拆分 创建src/app/index.js const Koa require(koa)const userRouter require(../router/user.route)const app new Koa()app.use(userRouter.routes())module.exports app改写main.js const { APP_PORT } require(./config/config.default)const app require(./app)app.listen(APP_PORT, () {console.log(server is running on http://localhost:${APP_PORT}) })2 将路由和控制器拆分 路由: 解析 URL, 分布给控制器对应的方法 控制器: 处理不同的业务 改写user.route.js const Router require(koa-router)const { register, login } require(../controller/user.controller)const router new Router({ prefix: /users })// 注册接口 router.post(/register, register)// 登录接口 router.post(/login, login)module.exports router创建controller/user.controller.js class UserController {async register(ctx, next) {ctx.body 用户注册成功}async login(ctx, next) {ctx.body 登录成功} }module.exports new UserController()六. 解析 body 1 安装 koa-body npm i koa-body2 注册中间件 改写app/index.js 3 解析请求数据 改写user.controller.js文件 const { createUser } require(../service/user.service)class UserController {async register(ctx, next) {// 1. 获取数据// console.log(ctx.request.body)const { user_name, password } ctx.request.body// 2. 操作数据库const res await createUser(user_name, password)// console.log(res)// 3. 返回结果ctx.body ctx.request.body}async login(ctx, next) {ctx.body 登录成功} }module.exports new UserController()4 拆分 service 层 service 层主要是做数据库处理 创建src/service/user.service.js class UserService {async createUser(user_name, password) {// todo: 写入数据库return 写入数据库成功} }module.exports new UserService()5 洋葱模型 洋葱模型就是将数据顺序传入到多个中间件中让它们进行处理传递并利用函数递归的特性让我们可以在一个中间件内先执行前半部分逻辑再执行之后的所有中间件的完整逻辑后再掉转方向继续执行这个中间件的后半部分。 const Koa require(koa); const app new Koa();// 中间件1 app.use((ctx, next) {console.log(1);next();console.log(1); });// 中间件 2 app.use((ctx, next) {console.log(2);next();console.log(2); });// 中间件 3 app.use((ctx, next) {console.log(3);next();console.log(3); }); app.listen(8000, 0.0.0.0, () {console.log(Server is starting); });在 koa 中中间件被 next() 方法分成了两部分。next() 方法上面部分会先执行下面部门会在后续中间件执行全部结束之后再执行。可以通过下图直观看出 输出的结果 1 2 3 3 2 1const Koa require(koa); const app new Koa();// 中间件1 app.use(async(ctx, next) {console.log(1);await next();console.log(1); });// 中间件 2 app.use(async(ctx, next) {console.log(2);const axios require(axios) const res await axios.get(http://www.baidu.com)next();console.log(2); });// 中间件 3 app.use((ctx, next) {console.log(3);next();console.log(3); }); app.listen(8000, 0.0.0.0, () {console.log(Server is starting); });七. 集成 sequlize sequelize ORM 数据库工具 当我们在开发 Node.js 应用程序时经常需要与数据库进行交互来存储和检索数据。这时候Sequelize就成了我们的得力助手。Sequelize是一个强大的ORM对象关系映射库它帮助我们以更直观的方式操作数据库而无需编写复杂的SQL查询语句。 简单来说ORM是一种编程技术让我们能够使用面向对象的方法来处理数据库。而Sequelize正是为此而生。它让我们可以用JavaScript代码定义模型和数据之间的关系就像在创建类和对象一样简单。每个模型类对应数据库中的一张表而实例则是表中的记录。 Sequelize的好处不胜枚举。首先它支持多种流行的数据库比如 PostgreSQL、MySQL、SQLite和MSSQL让我们在选择数据库时更加灵活。其次Sequelize允许我们在模型上设置验证规则确保数据的合法性和完整性。这为我们避免了许多繁琐的数据验证工作让数据操作更加安全可靠。 查询构建是Sequelize的又一个亮点。它提供了一套流畅的查询构建器让我们可以轻松地创建复杂的数据库查询。不再需要手动编写冗长的SQL语句Sequelize可以帮我们处理这些细节让我们专注于业务逻辑的实现。 如果你担心数据库模式的变更会让开发变得混乱别担心Sequelize还支持数据库迁移让我们可以轻松地管理数据库模式的更新和变更。这样我们可以在应用程序的生命周期中保持数据库结构的清晰和一致。 最后Sequelize还提供了强大的关联功能让我们可以轻松地定义模型之间的关联关系比如一对一、一对多、多对多等。这样的话我们可以轻松地进行跨表查询从而更加高效地处理复杂的数据需求。 总的来说Sequelize是一个非常强大且灵活的Node.js ORM库。它简化了数据库操作提高了开发效率并且让我们的代码更易于维护。无论是开发小型应用还是大型项目Sequelize都能成为我们最好的朋友让我们更加专注于业务逻辑的实现而不用为繁杂的数据库操作而烦恼。 能让我们以面向对象的方式去操作数据库 ORM: 对象关系映射 数据表映射(对应)一个类数据表中的数据行(记录)对应一个对象数据表字段对应对象的属性数据表的操作对应对象的方法 1 安装 sequelize npm i mysql2 sequelize2 连接数据库 src/db/seq.js const { Sequelize } require(sequelize)const {MYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PWD,MYSQL_DB, } require(../config/config.default)const seq new Sequelize(MYSQL_DB, MYSQL_USER, MYSQL_PWD, {host: MYSQL_HOST,dialect: mysql, })seq.authenticate().then(() {console.log(数据库连接成功)}).catch((err) {console.log(数据库连接失败, err)})module.exports seq3 编写配置文件 第一种方式 const dotenv require(dotenv)dotenv.config() // process.env 根据目录识别的 // ../config/config_default.js // module.export {key:value} 第一种方式 module.exports {MYSQL_HOST: localhost,MYSQL_PORT: 3306,MYSQL_USER: root,MYSQL_PWD: root,MYSQL_DB: auth,APP_PORT:3000 };// module.exportsprocess.env 第二种方式 const dotenv require(dotenv)dotenv.config() // process.env 根据目录识别的 // ../config/config_default.js // module.export {key:value} 第一种方式 // module.exports { // MYSQL_HOST: localhost, // MYSQL_PORT: 3306, // MYSQL_USER: root, // MYSQL_PWD: root, // MYSQL_DB: auth, // APP_PORT:3000 // };module.exportsprocess.env APP_PORT3001MYSQL_HOSTlocalhost MYSQL_PORT3306 MYSQL_USERroot MYSQL_PWDroot MYSQL_DBauth八. 创建 User 模型 1 拆分 Model 层 sequelize 主要通过 Model 对应数据表 创建src/model/user.model.js const { DataTypes } require(sequelize); const seq require(../db/db_sequ);const User seq.define(zd_user, {user_name: {type: DataTypes.STRING,allowNull: false,},password: {type: DataTypes.STRING,allowNull: false,},is_admin: {type: DataTypes.INTEGER,defaultValue: 0,}, }, {tableName: zd_user,timestamps: false, });module.exports User;对应sql -- auth.zd_user definitionCREATE TABLE zd_user (id int(11) NOT NULL AUTO_INCREMENT,user_name varchar(255) NOT NULL,password varchar(255) NOT NULL,is_admin int(1) DEFAULT 0,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT6 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;INSERT INTO auth.zd_user (id, user_name, password, is_admin) VALUES(5, root, root123, 0); 九. 添加用户入库 所有数据库的操作都在 Service 层完成, Service 调用 Model 完成数据库操作 改写src/service/user.service.js const User require(../model/use.model)class UserService {async createUser(user_name, password) {// 插入数据// User.create({// // 表的字段// user_name: user_name,// password: password// })// await表达式: promise对象的值const res await User.create({ user_name, password })// console.log(res)return res.dataValues} }module.exports new UserService()同时, 改写user.controller.js const { createUser } require(../service/user.service)class UserController {async register(ctx, next) {// 1. 获取数据// console.log(ctx.request.body)const { user_name, password } ctx.request.body// 2. 操作数据库const res await createUser(user_name, password)// console.log(res)// 3. 返回结果ctx.body {code: 0,message: 用户注册成功,result: {id: res.id,user_name: res.user_name,},}}async login(ctx, next) {ctx.body 登录成功} }module.exports new UserController()十. 错误处理 在控制器中, 对不同的错误进行处理, 返回不同的提示错误提示, 提高代码质量 const { createUser,getUerInfo } require(../service/user.service)// 发起请求 -》 controller -》 service --》 model -》 操作数据 -》 //使用了 sequelize 完成对数据的保存操作 class UserController {// 方法被 async 修饰了调用处必须加上awaitasync register(ctx, next) {// 1. 获取数据// console.log(ctx.request.body)const { username, password } ctx.request.body// 合法性if (!username || !password) {console.error(用户名或密码为空, ctx.request.body)ctx.status 400ctx.body {code: 10001,message: 用户名或密码为空,result: ,}return}// 合理性if (await getUerInfo({ user_name:username })) {ctx.status 409ctx.body {code: 10002,message: 用户已经存在,result: ,}return}// 2. 操作数据库const res await createUser(username, password)// console.log(res)// 3. 返回结果ctx.body {code: 0,message: 用户注册成功,result: {id: res.id,user_name: res.user_name,},}}async login(ctx, next) {ctx.body 登录成功}}module.exports new UserController()在 service 中封装函数 const User require(../model/user.model)// Service 处理了业务逻辑 class UserService {async createUser(user_name, password) {const userData { user_name, password };const res await User.create(userData);return res;}// 查询 用户名是否存在 trueasync getUerInfo({ id, user_name, password, is_admin }) {const whereOpt {} console.log(user_name:,user_name)id Object.assign(whereOpt, { id })user_name Object.assign(whereOpt, { user_name })// User.findOne 查询 用户名是否存在const res await User.findOne({attributes: [id, user_name, password, is_admin],where: whereOpt,})return res ? res.dataValues : null}}module.exports new UserService()十一. 拆分中间件 为了使代码的逻辑更加清晰, 我们可以拆分一个中间件层, 封装多个中间件函数 1 拆分中间件 添加src/middleware/user.middleware.js const { getUerInfo } require(../service/user.service) const { userFormateError, userAlreadyExited } require(../constant/err.type)const userValidator async (ctx, next) {const { user_name, password } ctx.request.body// 合法性if (!user_name || !password) {console.error(用户名或密码为空, ctx.request.body)// 抛出给下方报错的地方ctx.app.emit(error, userFormateError, ctx)return}await next() }const verifyUser async (ctx, next) {const { user_name } ctx.request.bodyif (getUerInfo({ user_name })) {// 抛出给报错的地方ctx.app.emit(error, userAlreadyExited, ctx)return}await next() }module.exports {userValidator,verifyUser, }2 统一错误处理 在出错的地方使用ctx.app.emit提交错误在 app 中通过app.on监听 编写统一的错误定义文件 module.exports {userFormateError: {code: 10001,message: 用户名或密码为空,result: ,},userAlreadyExited: {code: 10002,message: 用户已经存在,result: ,}, }3 错误处理函数 module.exports (err, ctx) {let status 500switch (err.code) {case 10001:status 400breakcase 10002:status 409breakdefault:status 500}ctx.status statusctx.body err }改写app/index.js const errHandler require(./errHandler) // 统一的错误处理 app.on(error, errHandler)// 注册接口 router.post(/register, userValidator, verifyUser, register)十二. 加密 bcryptjs 是Node.js中比较简洁好用的一款第三方加盐salt加密包并且支持跨平台的特性用于实现在Node环境下重要资源的加密。 由它加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是8至56个字符并将在内部被转化为448位的密钥。 在将密码保存到数据库之前, 要对密码进行加密处理 123123abc (加盐) 加盐加密 1 安装 bcryptjs npm i bcryptjs2 编写加密中间件 const crpytPassword async (ctx, next) {const { password } ctx.request.bodyconst salt bcrypt.genSaltSync(10)// hash保存的是 密文const hash bcrypt.hashSync(password, salt)ctx.request.body.password hashawait next() }const verifyUser async (ctx, next) {const { username } ctx.request.body// if (await getUerInfo({ user_name })) {// ctx.app.emit(error, userAlreadyExited, ctx)// return// }try {const res await getUerInfo({ user_name:username })if (res) {console.error(用户名已经存在, { username })ctx.app.emit(error, userAlreadyExited, ctx)return}} catch (err) {console.error(获取用户信息错误, err)ctx.app.emit(error, userRegisterError, ctx)return}await next() }3 在 router 中使用 改写user.router.js const Router require(koa-router)const {userValidator,verifyUser,crpytPassword, } require(../middleware/user.middleware) const { register, login } require(../controller/user.controller)const router new Router({ prefix: /users })// 注册接口 router.post(/register, userValidator, verifyUser, crpytPassword, register)// 登录接口 router.post(/login, login)module.exports router十三. 登录验证 流程: 验证格式验证用户是否存在验证密码是否匹配 改写src/middleware/user.middleware.js const bcrypt require(bcryptjs)const { getUerInfo } require(../service/user.service) const {userFormateError,userAlreadyExited,userRegisterError,userDoesNotExist,userLoginError,invalidPassword, } require(../constant/err.type)const userValidator async (ctx, next) {const { user_name, password } ctx.request.body// 合法性if (!user_name || !password) {console.error(用户名或密码为空, ctx.request.body)ctx.app.emit(error, userFormateError, ctx)return}await next() }const verifyUser async (ctx, next) {const { user_name } ctx.request.body// if (await getUerInfo({ user_name })) {// ctx.app.emit(error, userAlreadyExited, ctx)// return// }try {const res await getUerInfo({ user_name })if (res) {console.error(用户名已经存在, { user_name })ctx.app.emit(error, userAlreadyExited, ctx)return}} catch (err) {console.error(获取用户信息错误, err)ctx.app.emit(error, userRegisterError, ctx)return}await next() }const crpytPassword async (ctx, next) {const { password } ctx.request.bodyconst salt bcrypt.genSaltSync(10)// hash保存的是 密文const hash bcrypt.hashSync(password, salt)ctx.request.body.password hashawait next() }const verifyLogin async (ctx, next) {// 1. 判断用户是否存在(不存在:报错)const { user_name, password } ctx.request.bodytry {const res await getUerInfo({ user_name })if (!res) {console.error(用户名不存在, { user_name })ctx.app.emit(error, userDoesNotExist, ctx)return}// 2. 密码是否匹配(不匹配: 报错)if (!bcrypt.compareSync(password, res.password)) {ctx.app.emit(error, invalidPassword, ctx)return}} catch (err) {console.error(err)return ctx.app.emit(error, userLoginError, ctx)}await next() }module.exports {userValidator,verifyUser,crpytPassword,verifyLogin, }定义错误类型 module.exports {userFormateError: {code: 10001,message: 用户名或密码为空,result: ,},userAlreadyExited: {code: 10002,message: 用户已经存在,result: ,},userRegisterError: {code: 10003,message: 用户注册错误,result: ,},userDoesNotExist: {code: 10004,message: 用户不存在,result: ,},userLoginError: {code: 10005,message: 用户登录失败,result: ,},invalidPassword: {code: 10006,message: 密码不匹配,result: ,}, }改写路由 // 登录接口 router.post(/login, userValidator, verifyLogin, login)十四. 用户的认证 官方介绍JSON Web TokenJWT是一种开放标准RFC 7519它定义了一种紧凑且自包含的方式用于在各方之间作为JSON对象安全地传输信息。此信息可以验证和信任因为它是数字签名的。JWT可以使用秘密使用HMAC算法或使用RSA或ECDSA的公钥/私钥对签名。 https://jwt.io/ 登录成功后, 给用户颁发一个令牌 token, 用户在以后的每一次请求中携带这个令牌. jwt: jsonwebtoken header: 头部payload: 载荷signature: 签名 1 颁发 token 1) 安装 jsonwebtoken npm i jsonwebtoken2) 在控制器中改写 login 方法 async login(ctx, next) {const { user_name } ctx.request.body// 1. 获取用户信息(在token的payload中, 记录id, user_name, is_admin)try {// 从返回结果对象中剔除password属性, 将剩下的属性放到res对象const { password, ...res } await getUerInfo({ user_name })ctx.body {code: 0,message: 用户登录成功,result: {token: jwt.sign(res, JWT_SECRET, { expiresIn: 1d }),},}} catch (err) {console.error(用户登录失败, err)} }3) 定义私钥 在.env定义 JWT_SECRET xzd2 用户认证 1) 创建 auth 中间件 const jwt require(jsonwebtoken)const { JWT_SECRET } require(../config/config.default)const { tokenExpiredError, invalidToken } require(../constant/err.type)const auth async (ctx, next) {const { authorization } ctx.request.headerconst token authorization.replace(Bearer , )console.log(token)try {// user中包含了payload的信息(id, user_name, is_admin)const user jwt.verify(token, JWT_SECRET)ctx.state.user user} catch (err) {switch (err.name) {case TokenExpiredError:console.error(token已过期, err)return ctx.app.emit(error, tokenExpiredError, ctx)case JsonWebTokenError:console.error(无效的token, err)return ctx.app.emit(error, invalidToken, ctx)}}await next() }module.exports {auth, }登录生成 toekn 后 后续任意接口都需要携带 token 进行 访问 2) 改写 router 具体操作之前 验签 // 修改密码接口 router.patch(/, auth, (ctx, next) {console.log(ctx.state.user)ctx.body 修改密码成功 })十五 接口练习 安装依赖 {name: test,version: 1.0.0,main: index.js,license: MIT,dependencies: {dotenv: ^16.3.1,koa: ^2.14.2,koa-router: ^11.0.2,mysql2: ^2.2.5,nodemon: ^3.0.1},scripts: {dev: nodemon ./main.js} } 数据库名称 test_spiritmark_db 数据库用户 admin_spiritmark 数据库密码 55726955c65bd84c 数据库地址 mysql.sqlpub.com:3306 注册邮箱 liuluchangcathay-ins.com.cn 注意 密码只显示一次请注意保存。 为保障数据库运行安全密码严禁泄漏到公共环境如csdn、zhihu、github等发现即永久锁定。 测试sql CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, age INT NOT NULL );INSERT INTO users (name, age) VALUES (John Doe, 25), (Jane Smith, 30), (Mike Johnson, 35);select * from users;启动应用 const Koa require(koa); const Router require(koa-router); const mysql require(mysql2/promise);const app new Koa(); const router new Router();// 创建数据库连接池 const pool mysql.createPool({host: mysql.sqlpub.com,user: admin_spiritmark,port:3306,password: 55726955c65bd84c,database: test_spiritmark_db, });// 添加数据 router.post(/api, async (ctx) {const { name, age } ctx.request.body;try {const [result] await pool.query(INSERT INTO users (name, age) VALUES (?, ?), [name, age]);ctx.body result;} catch (error) {ctx.status 500;ctx.body error.message;} });// 删除数据 router.del(/api/:id, async (ctx) {const { id } ctx.params;try {const [result] await pool.query(DELETE FROM users WHERE id ?, [id]);ctx.body result;} catch (error) {ctx.status 500;ctx.body error.message;} });// 更新数据 router.put(/api/:id, async (ctx) {const { id } ctx.params;const { name, age } ctx.request.body;try {const [result] await pool.query(UPDATE users SET name ?, age ? WHERE id ?, [name, age, id]);ctx.body result;} catch (error) {ctx.status 500;ctx.body error.message;} });// 查询数据 router.get(/api, async (ctx) {const page parseInt(ctx.query.page) || 1;const size parseInt(ctx.query.size) || 10;const offset (page - 1) * size;try {const [rows] await pool.query(SELECT * FROM users LIMIT ?, ?, [offset, size]);ctx.body rows;} catch (error) {ctx.status 500;ctx.body error.message;} });// 启动应用程序 app.use(router.routes()).use(router.allowedMethods());const PORT 3000; app.listen(PORT, () {console.log(Server is running on port ${PORT}); });封装优化 const Koa require(koa); const Router require(koa-router); const mysql require(mysql2/promise);const app new Koa(); const router new Router();// 创建数据库连接池 const createPool () {return mysql.createPool({host: mysql.sqlpub.com,user: admin_spiritmark,port:3306,password: 55726955c65bd84c,database: test_spiritmark_db,}); };// 添加数据 const addUser async (name, age) {const pool createPool();try {const [result] await pool.query(INSERT INTO users (name, age) VALUES (?, ?), [name, age]);return result;} catch (error) {throw new Error(error.message);} finally {pool.end();} };// 删除数据 const deleteUser async (id) {const pool createPool();try {const [result] await pool.query(DELETE FROM users WHERE id ?, [id]);return result;} catch (error) {throw new Error(error.message);} finally {pool.end();} };// 更新数据 const updateUser async (id, name, age) {const pool createPool();try {const [result] await pool.query(UPDATE users SET name ?, age ? WHERE id ?, [name, age, id]);return result;} catch (error) {throw new Error(error.message);} finally {pool.end();} };// 查询数据 const getUsers async (page 1, size 10) {const pool createPool();const offset (page - 1) * size;try {const [rows] await pool.query(SELECT * FROM users LIMIT ?, ?, [offset, size]);return rows;} catch (error) {throw new Error(error.message);} finally {pool.end();} };// 添加数据 router.post(/api, async (ctx) {const { name, age } ctx.request.body;try {const result await addUser(name, age);ctx.body result;} catch (error) {ctx.status 500;ctx.body error.message;} });// 删除数据 router.del(/api/:id, async (ctx) {const { id } ctx.params;try {const result await deleteUser(id);ctx.body result;} catch (error) {ctx.status 500;ctx.body error.message;} });// 更新数据 router.put(/api/:id, async (ctx) {const { id } ctx.params;const { name, age } ctx.request.body;try {const result await updateUser(id, name, age);ctx.body result;} catch (error) {ctx.status 500;ctx.body error.message;} });// 查询数据 router.get(/api, async (ctx) {const page parseInt(ctx.query.page) || 1;const size parseInt(ctx.query.size) || 10;try {const rows await getUsers(page, size);ctx.body rows;} catch (error) {ctx.status 500;ctx.body error.message;} });// 启动应用程序 app.use(router.routes()).use(router.allowedMethods());const PORT 3000; app.listen(PORT, () {console.log(Server is running on port ${PORT}); });十六 koa集成 模板引擎 EJS 的使用 使用模板引擎 # 在项目中下载koa-views包 npm i koa-views # 在项目中下载ejs包 npm i ejs入口index.js const Koa require(koa); const Router require(koa-router); const app new Koa(); const router new Router(); // 1. 引入koa-views const views require(koa-views); // 2. 配置模板引擎中间件views()第一个参数是视图模板所在的路径第二个参数是应用ejs模板引擎 app.use(views(views, { extension: ejs })); // 若这样配置模板的后缀名是.ejs //app.use(views(views, { map: { html: ejs } })); // 若这样配置模板的后缀名是.html// 我们需要在每个路由的render中都渲染一个公共的数据 // 写一个中间件配置公共信息 app.use(async (ctx, next) {// 公共的数据要放在ctx.state中ctx.state {userinfo: 张三,age: 18,}await next() })router.get(/, async (ctx, next) {let title 你好ejs// 3. 异步渲染模板await ctx.render(index.ejs, {// 绑定数据title: title}) })router.get(/news, async (ctx, next) {let arr [111111, 22222, 444444]let content h2这是一个h2/h2let num 123await ctx.render(news.ejs, {list: arr,content: content,num: num}) });app.use(router.routes()); app.use(router.allowedMethods());app.listen(3000, () {console.log(starting at port 3000); });/views/index.ejs html langen headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleejs模板引擎/title /head body%- include(./public/header.ejs) %这是一个ejs模板引擎h2%title%-----%userinfo%/h2 /body /html/views/news.ejs html langen headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleejs数据绑定/title /head bodyh2引入外部模块/h2%- include(./public/header.ejs) %h2ejs循环渲染数据/h2ul%for(var i0;ilist.length;i){%li%list[i]%/li%}%/ulh2绑定html数据/h2%-content%h2条件判断/h2% if(num24){ %大于24%} else{ % 小于24%} %h2公共数据/h2%userinfo% /body /htmlart-template 原始语法和ejs一模一样都用% %标准语法用的是{{ }}这里代码示例用的是标准语法。 安装所需包 npm install --save art-template npm install --save koa-art-template入口index.js const Koa require(koa); const Router require(koa-router); const app new Koa(); const router new Router(); const path require(path); // 1. 引入koa-art-template const render require(koa-art-template); // 2. 配置art-template模板引擎 render(app, {root: path.join(__dirname, views), // 视图的位置extname: .html, // 后缀名debug: process.env.NODE_ENV ! production // 是否开启调试模式 });// 我们需要在每个路由的render中都渲染一个公共的数据 // 写一个中间件配置公共信息 app.use(async (ctx, next) {// 公共的数据要放在ctx.state中ctx.state {userinfo: 张三,age: 18,}await next() })router.get(/, async (ctx, next) {let title 你好koa-art-template// 3. 异步渲染模板await ctx.render(index, {// 绑定数据title: title}) })router.get(/news, async (ctx, next) {let arr [111111, 22222, 444444]let content h2这是一个h2/h2let num 123await ctx.render(news, {list: arr,content: content,num: num}) });app.use(router.routes()); app.use(router.allowedMethods());app.listen(3000, () {console.log(starting at port 3000); });/views/news.html html langen headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title数据绑定/title /head bodyh2引入外部模块/h2{{include ./public/header.html}}h2绑定数据/h2{{list.name}}h2公共数据/h2{{userinfo}}h2绑定html数据/h2{{list.h}}h2条件判断/h2{{if num20}}span大于20/span{{else}}span小于20/span{{/if}}h2循环渲染数据/h2ul{{each list.data}}li{{$index}}--{{$value}}/li{{/each}}/ul /body /html
http://www.pierceye.com/news/343230/

相关文章:

  • 网站正在建设中亚洲wamp 设置多个网站
  • 网上注册公司流程及材料sem seo是什么意思呢
  • 网站开发后所有权广州市官网网站建设
  • 公司网站宣传设计北京市住房与建设厅官方网站
  • 企业信息化建设如何帮助客户理解网站流量怎么给自己网站做搜索框
  • 公司网站不续费农村未来10大暴利行业
  • 代做设计网站好跨境电商排名
  • 网站备案状态查询东莞智通人才市场招聘官网
  • 做微网站要多少钱更合网站设计制作
  • 网站如何留住客户企业建设网站需要注意什么
  • 中国最受欢迎的网站网站建设要知道的
  • 软件开发公司网站模板天津网站建设方案报价
  • 做面条的网站旅游网络营销如何做
  • 知乎的网站建设和网站运营网站建设需求说明
  • 天津做陶瓷的公司网站番禺核酸检测定点医院名单
  • 教育网站赏析delphi网站开发教程
  • 电商网站设计说明书php网站服务器架设
  • 精品课程网站开发项目电子商务的分类
  • 网站建设成品动漫网站建设答辩ppt
  • 邯郸网站设计价格做网站哪便宜
  • 建设网站的一般步骤网站设计下载
  • 广东同江医院网站建设建站网站图片不显示
  • 免费在线响应式网站自助建站网站网页怎么设计
  • 池州网站建设抚顺网站建设公司
  • 网站如可引导客户义乌小程序开发制作公司
  • 环境设计排版素材网站周口市住房和城乡建设局网站
  • 建设部资质查询网站wordpress采集英文
  • 深圳北站设计方案高质量网站外链平台
  • 苏州做网站优化的公司国外 网站页面
  • 网站建设流程发布网站和网页制作鲜花网站建设论文百度文库