如何发送HTTP响应
拿到GET过来的数据
在 Koa 中,HTTP 请求对象 ctx.request 包含了客户端发送给服务器的所有请求信息,包括请求头、请求体、请求参数等。其中,请求体中包含了客户端发送给服务器的请求数据,例如表单数据、JSON 数据等。我们在获取GET请求过来的参数时一般有两种方式: ctx.request.query和ctx.query
const koa = require('koa')
const Router = require('koa-router')
router.get('/del', async (ctx) => {
//以下两种都可以接受get请求的参数
const { id } = ctx.request.query
const { id1 } = ctx.query
console.log(id, id1, id2);
// ctx.body = '用户列表页'
/**
* ctx.set 方法接受两个参数,
* 第一个参数是要设置的 HTTP 响应头的键(header name),
* 第二个参数是要设置的 HTTP 响应头的值(header value)
* */
ctx.set("Allow", "GET,POST")//可以设置响应头和请求方式
ctx.status = 301,//可以设置他的返回状态码
ctx.body = {//可以通过body响应一个JSON对象
code: 200,
msg: '这是请求首页信息'
}
})
app.use(router.routes())
app.listen(3000)
设置响应头
const koa = require('koa')
const Router = require('koa-router')
router.get('/del', async (ctx) => {
/**
* ctx.set 方法接受两个参数,
* 第一个参数是要设置的 HTTP 响应头的键(header name),
* 第二个参数是要设置的 HTTP 响应头的值(header value)
* */
ctx.set("Allow", "GET,POST")//可以设置响应头和请求方式
ctx.status = 301,//可以设置他的返回状态码
ctx.body = {//可以通过body相应一个JSON对象
code: 200,
msg: '这是请求首页信息'
}
})
app.use(router.routes())
app.listen(3000)
如何拿POST过来的数据
POST过来的参数获取和GET有区别,主要区别在于post请求需要利用一个中间件(body-parse),把请求体解析成js对象,并挂载到ctx的.request.body属性上,我们才能对其操作
const koa = require('koa')
const Router = require('koa-router')
//先引入body-parse
const bodyparser = require('koa-bodyparser')
router.post('/add', async (ctx) => {
//接受post请求的参数
/*
body-parser 是 Node.js 中一个常用的请求体解析库,
它可以将请求体数据解析成 JavaScript 对象,
并将其挂载到 req.body 上,方便我们在路由处理函数中进行访问和处理。
*/
const { username, pwd } = ctx.request.body
console.log(username, pwd);
ctx.body = '添加用户'
})
app.use(bodyparser())//这里需要注意的是需要先调用bodyparse再use routes,否则数据体无法正确解析
app.use(router.routes())
app.listen(3000)
如何拿路由携带的参数
在 Web 应用程序中,路由参数(Route Parameter)是指嵌入在 URL 路径中的变量,用于标识资源的唯一标识符或其他相关信息。在 Koa 中,路由参数可以通过冒号 : 开头的占位符来定义,例如 /find/:id 中的 :id 就表示一个路由参数。
//这种是直接跟在路径后面的路由参数
router.get('/find/:id', async (ctx) => {
let id = ctx.params.id
console.log(id);
})
如何设置错误处理
koa自带的方法
ctx.throw(412, '先决条件失败')ctx.throw是服务端抛出异常的函数
封装一个中间件来处理错误
利用trycatch进行封装
app.use((ctx,err){
try(){}catch(err){}
})
使用插件
koa-json-error,安装koa-json-error,让服务端可以抛出比较完善的错误信息
{
"message": "先决条件失败",
"name": "PreconditionFailedError",
"stack": "PreconditionFailedError: 先决条件失败\n at Object.throw (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\koa\\lib\\context.js:97:11)\n at D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\app.js:31:18\n at dispatch (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\.store\\koa-compose@4.1.0\\node_modules\\koa-compose\\index.js:42:32)\n at D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\.store\\koa-router@12.0.0\\node_modules\\koa-router\\lib\\router.js:425:16\n at dispatch (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\.store\\koa-compose@4.1.0\\node_modules\\koa-compose\\index.js:42:32)\n at D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\.store\\koa-compose@4.1.0\\node_modules\\koa-compose\\index.js:34:12\n at dispatch (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\.store\\koa-router@12.0.0\\node_modules\\koa-router\\lib\\router.js:430:31)\n at dispatch (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\koa-compose\\index.js:42:32)\n at jsonError (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\.store\\koa-json-error@3.1.2\\node_modules\\koa-json-error\\lib\\middleware.js:49:12)\n at dispatch (D:\\MyNecessaryFile\\A技术学习\\koa2-study\\myKoa\\node_modules\\koa-compose\\index.js:42:32)",
"status": 412
}
如何连接到数据库,以Mango为例
- 创建一个db(数据库)文件夹,并创建index.js,引入
mangoose,告诉node我正在使用mongodb数据库const mongoose = require('mongoose') - 向外导出模块
module.exports = () => { //connect连接到数据库,他有两个参数,一个是数据库的地址,第二个是相关配置 /**useNewUrlParser是 Mongoose 连接 MongoDB 数据库时的一个选项, 用于告诉 Mongoose 使用 MongoDB 连接字符串中的新的解析器(parser)。 */ mongoose.connect('mongodb://localhost:27017/demo', { useNewUrlParser: true }).then(() => { console.log('数据库连接成功'); }).catch(err => { console.log('账号连接失败', err); }) }
如何使用MongoDB封装一个增删改查逻辑层
Step1封装公有操作
我们可以封装一个CRUDUtil,用来存放基本的增删改查操作。
/**
* 这里是一些公共的crud方法
*/
const models = require('../../models')
/**
*
* 用于查询数据的公共方法
* @param {*} model 模型对象
* @param {*} ctx context
* @param {*} where 条件
* @returns
*/
const find = (model, ctx, where) => {//传入两个模块,查找的目标,属于哪个模块,where:查询对象
return model.find(where || {}).then(//where:条件查询
(rel) => {
console.log(ctx);
if (rel != null && rel.length > 0) {
ctx.body = {
result: JSON.parse(JSON.stringify(rel))
}
} else {
ctx.body = {
code: 404,
msg: '未找到指定数据'
}
}
}).catch(err => {
ctx.body = {
code: 400,
msg: '查询时出错'
}
console.error(err);
})
}
/**
* 添加数据的公共方法
* @param {*} model
* @param {*} params
* @param {*} ctx
* @returns
*/
const add = (model, params, ctx) => {
// create()用于向MongoDB中的Users集合中插入一条新的文档
return model.create(params).then((rel) => { //调用这个模板的create方法
if (rel) {
ctx.body = {
code: 200,
msg: '添加成功',
rel
}
} else {
ctx.body = {
code: 300,
msg: '添加失败'
}
}
}).catch((err) => {
ctx.body = {
code: 400,
msg: '添加出现异常'
}
console.error(err);
})
}
const update = (model, where, params, ctx) => {
return model.updateOne(where, params).then(rel => {
if (rel != null) {
ctx.body = {
code: 200,
msg: '修改成功'
}
}
}).catch(err => {
ctx.body = {
code: 400,
msg: '修改时出现异常'
}
console.error(err);
})
}
/**
* 用于数据删除的公共方法
* @param {*} model
* @param {*} where
* @param {*} ctx
*/
const del = (model, where, ctx) => {
model.findByIdAndDelete(where).then(rel => {
ctx.body = {
result: rel
}
}).catch(err => {
ctx.body = {
code: 400,
msg: '删除异常'
}
console.error(err)
})
}
/**
* 用于查询单个数据的公共方法
* @param {*} model
* @param {*} where
* @param {*} ctx
*/
const findOne = (model, where, ctx) => {
return model.findOne(where || {}).then(rel => {
if (rel != null) {
ctx.body = {
result: JSON.parse(JSON.stringify(rel))
}
} else {
ctx.body = {
code: 404,
msg: '未找到指定数据'
}
}
}).catch(err => {
ctx.body = {
code: 400,
msg: '查询时出错'
}
console.error(err)
})
}
module.exports = {
find,
add,
update,
del,
findOne
}
以上代码暂未对模糊查询等find方法进行封装,目前仅实现了查询单条数据的功能。
Step2在具体逻辑实现层调用封装好的crud方法
在实现逻辑的userController调用先前封装好的方法,以减少冗余的代码
const { Users } = require('../models');
const crud = require('./CRUDUtil/index');
const userAdd = async (ctx) => {
let params = ctx.request.body || null;
await crud.add(Users, params, ctx);
};
const userDel = async (ctx) => {
let { _id } = ctx.request.body || null;
let result = await crud.del(Users, { _id }, ctx);
ctx.body = result;
};
const userUpdate = async (ctx) => {
let params = ctx.request.body || null;
await crud.update(Users,
{ _id: params._id },
{
userAccount: params.userAccount,
userPassword: params.userPassword,
userAvatar: params.userAvatar,
userName: params.userName,
updateTime: new Date()
},
ctx
);
};
const userFindAll = async (ctx) => {
await crud.find(Users, (ctx ? ctx : {}), null);
};
const userFind = async (ctx) => {
await crud.findOne(Users, { _id: ctx.params.id }, ctx || null);
};
module.exports = {
userAdd,
userDel,
userUpdate,
userFindAll,
userFind
};
总结
这样处理我们的代码一是能让我们的代码看起来更整洁,也将逻辑层与具体的基本操作函数分离,更符合resful,代码维护性更强。