简单的开始
npm i koa --save
const Koa = require('koa');
const app = new Koa();
app.use((ctx) => {
ctx.body = 'hello Koa';
});
app.listen(3000, () => {
console.log('程序从3000端口启动了!');
});
这样,就可以从localhost:3000访问到服务了
洋葱模型
const Koa = require("koa");
const app = new Koa();
app.use(async (ctx, next) => {
console.log("1");
await next();
console.log("5");
});
app.use(async (ctx, next) => {
console.log("2");
await next();
console.log("4");
});
app.use((ctx) => {
console.log("3");
});
app.listen(3000, () => {
console.log("程序从3000端口启动了!");
});
在运行时,当碰到await next()停下来去执行下一层逻辑,当执行完成后再回来继续执行
路由中间件
npm i koa-router --save
const Koa = require("koa");
const KoaRouter = require("koa-router");
const app = new Koa();
const router = new KoaRouter();
// const userRouter = new KoaRouter({prefix: "/user"})
app.use(router.routes());
app.use(router.allowedMethods());
router.get("/user", (ctx) => {
ctx.body = "get请求/user";
});
router.get("/user/:id", (ctx) => {
ctx.body = `get请求/user接口,路由参数为${ctx.params.id}`;
});
router.post("/user", (ctx) => {
ctx.body = "post请求/user接口";
});
app.listen(3000, () => {
console.log("程序从3000端口启动了!");
});
1,首先创建路由实例,在创建的时候,可以带入参数,如果带入prefix,可以在使用该实例做路由时,都带入路径中
2,然后需要使用的话,需要由app.use(router.routes())即可
3,app.use(router.allowedMethods())可以使用户在请求接口时使用allow知道目前接口所支持的方法,另如果使用其他方法请求接口返回405,代表支持该方法,但未设置,如果返回501即不支持该方法
参数
1,路由参数
router.get("/user/:id", (ctx) => {
ctx.body = `get请求/user接口,路由参数为${ctx.params.id}`;
});
通过ctx.params获取
2,get接口参数
router.get("/user", (ctx) => {
ctx.body = ctx.request.query;
});
通过ctx.request.query获取
3,post接口参数
npm i koa-body --save
const Koa = require("koa");
const KoaRouter = require("koa-router");
const KoaBody = require("koa-body");
const static = require("koa-static");
const path = require("path");
const parameter = require("koa-parameter");
const error = require("koa-json-error");
const jwt = require("jsonwebtoken");
const Koajwt = require("koa-jwt");
const app = new Koa();
const router = new KoaRouter();
const secret = "jwt-secret"; //jwt秘钥,自己更换
const userDB = [
{ id: 1, name: "zhangsan", password: 123, age: 18 },
{ id: 2, name: "lisi", password: 345, age: 18 },
];
app.use(
error({
postFormat: (e, { stack, ...obj }) =>
process.env.NODE_ENV === "production" ? obj : { stack, ...obj },
})
);
app.use(parameter(app));
app.use(
KoaBody({
multipart: true,
formidable: {
maxFieldsSize: 2 * 1024 * 1024,
uploadDir: path.resolve(__dirname, "./upload"),
keepExtensions: true,
},
})
);
app.use(static(__dirname, "./upload"));
app.use(
Koajwt({
secret: secret,
}).unless({ path: [/^\/login/] })
);
app.use(router.routes());
app.use(router.allowedMethods());
router.post("/login", (ctx) => {
ctx.verifyParams({
name: "string",
password: "number",
});
const user = userDB.find(({ name, password }) => {
return (
name === ctx.request.body.name && password === ctx.request.body.password
);
});
if (user) {
const token = jwt.sign(user, secret, { expiresIn: "1d" });
ctx.body = { token };
} else {
ctx.throw(401, "账号或密码错误!");
}
});
router.post("/img", (ctx) => {
ctx.body = {
imgUrl: `http://${ctx.request.host}/upload/${path.basename(
ctx.request.files.file.path
)}`,
};
});
router.get("/user", (ctx) => {
ctx.body = ctx.state.user;
});
app.listen(3000, () => {
console.log("程序从3000端口启动了!");
});
需要注意,此中间件调用位置需要置于路由中间件前面,接受参数用ctx.request.body
上面加上了接受图片的设置,设置multipart为true,接受图片,之后由formidable设置上传图片的maxFieldsSize大小,uploadDir存放路径,keepExtensions保存上传的后缀,上传后的文件存于ctx.request.file中,不是文件的参数存于ctx.request.body中,之后由koa-static让保存的图片,可以用链接访问(路径格式: http:// + 路由 + 图片路径 + 图片名字);
4,参数校验
npm i koa-parameter --save
规则使用链接
const Koa = require("koa");
const KoaRouter = require("koa-router");
const bodyParser = require("koa-bodyparser");
const parameter = require("koa-parameter");
const app = new Koa();
const router = new KoaRouter();
// const userRouter = new KoaRouter({prefix: "/user"})
app.use(parameter(app));
app.use(bodyParser());
app.use(router.routes());
app.use(router.allowedMethods());
router.get("/user", (ctx) => {
ctx.body = ctx.request.query;
});
router.post("/user", (ctx) => {
ctx.verifyParams({
name: "string",
age: { type: "number", required: false },
});
ctx.body = ctx.request.body;
});
app.listen(3000, () => {
console.log("程序从3000端口启动了!");
});
校验失败会直接返回状态码422,加以下信息
{
"message": "Validation Failed",
"errors": [
{
"message": "required",
"field": "name",
"code": "missing_field"
},
{
"message": "should be a number",
"code": "invalid",
"field": "age"
}
],
"params": {
"age": "1"
}
}
处理返回的错误信息
npm i koa-json-error --save
const Koa = require("koa");
const KoaRouter = require("koa-router");
const bodyParser = require("koa-bodyparser");
const parameter = require("koa-parameter");
const error = require("koa-json-error");
const app = new Koa();
const router = new KoaRouter();
// const userRouter = new KoaRouter({prefix: "/user"})
app.use(
error({
postFormat: (e, { stack, ...obj }) =>
process.env.NODE_ENV === "production" ? obj : { stack, ...obj },
})
);
app.use(parameter(app));
app.use(bodyParser());
app.use(router.routes());
app.use(router.allowedMethods());
router.get("/user", (ctx) => {
a.b
ctx.body = ctx.request.query;
});
router.post("/user", (ctx) => {
ctx.verifyParams({
name: "string",
age: { type: "number", required: false },
});
ctx.body = ctx.request.body;
});
app.listen(3000, () => {
console.log("程序从3000端口启动了!");
});
通过postFormat控制返回格式,在正式环境的时候将堆栈信息stack隐藏了,在上面中,get中有错误,当请求时,会发生500错误,错误信息如下
{
"stack": "ReferenceError: a is not defined\n at C:\\Users\\v_vjmpeng\\Desktop\\koa\\app\\index.js:22:3\n at dispatch (C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-compose\\index.js:42:32)\n at C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-router\\lib\\router.js:372:16\n at dispatch (C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-compose\\index.js:42:32)\n at C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-compose\\index.js:34:12\n at dispatch (C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-router\\lib\\router.js:377:31)\n at dispatch (C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-compose\\index.js:42:32)\n at bodyParser (C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-bodyparser\\index.js:95:11)\n at processTicksAndRejections (internal/process/task_queues.js:97:5)\n at async verifyParam (C:\\Users\\v_vjmpeng\\Desktop\\koa\\node_modules\\koa-parameter\\index.js:52:7)",
"name": "ReferenceError",
"message": "a is not defined",
"status": 500
}
jwt身份验证
npm i koa-jwt jsonwebtoken --save
const Koa = require("koa");
const KoaRouter = require("koa-router");
const bodyParser = require("koa-bodyparser");
const parameter = require("koa-parameter");
const error = require("koa-json-error");
const jwt = require("jsonwebtoken");
const Koajwt = require("koa-jwt");
const app = new Koa();
const router = new KoaRouter();
const secret = "jwt-secret"; //jwt秘钥,自己更换
const userDB = [
{ id: 1, name: "zhangsan", password: 123, age: 18 },
{ id: 2, name: "lisi", password: 345, age: 18 },
];
app.use(
error({
postFormat: (e, { stack, ...obj }) =>
process.env.NODE_ENV === "production" ? obj : { stack, ...obj },
})
);
app.use(parameter(app));
app.use(bodyParser());
app.use(
Koajwt({
secret: secret,
}).unless({ path: [/^\/login/] })
);
app.use(router.routes());
app.use(router.allowedMethods());
router.post("/login", (ctx) => {
ctx.verifyParams({
name: "string",
password: "number",
});
const user = userDB.find(({ name, password }) => {
return (
name === ctx.request.body.name && password === ctx.request.body.password
);
});
if (user) {
const token = jwt.sign(user, secret, { expiresIn: '1d' });
ctx.body = { token };
} else {
ctx.throw(401, "账号或密码错误!");
}
});
router.get("/user", (ctx) => {
ctx.body = ctx.state.user;
});
app.listen(3000, () => {
console.log("程序从3000端口启动了!");
});
koa-jwt需要配合jsonwebtoken一起使用,由jsonwebtoken拿着信息生成token返回给客户端,之后客户端每次请求都带上token,经过koa-jwt的校验,便能成功访问,注意,jsonwebtoken可以通过传入expiresIn控制过期时间,koa-jwt可以通过unless配置控制不想校验的路由.