Koa的基本使用记录

298 阅读4分钟

简单的开始

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配置控制不想校验的路由.