参考链接—->

koa middleware

  1. app.use(async (ctx, next) => {
  2. await next();
  3. ctx.response.type = 'text/html';
  4. ctx.response.body = '<h1>Hello, koa2!</h1>';
  5. });
  • ctx 是由koa传入的封装了 request 和 response 的变量,可以通过它访问request和response
  • next 是koa传入的将要处理的下一个 异步函数

为什么要调用 await next() ?

因为koa把很多 async 函数组成一个处理链,每个 async 函数都可以做一些自己的事情,然后 await next() 来调用下一个 async 函数。
每个async 函数成为 middleware,这些中间件可以组合起来。

  1. app.use(async (ctx, next) => {
  2. console.log('执行顺序 --- 1')
  3. console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
  4. await next(); // 调用下一个middleware
  5. console.log('执行顺序 --- 6')
  6. });
  7. app.use(async (ctx, next) => {
  8. console.log('执行顺序 --- 2')
  9. const start = new Date().getTime(); // 当前时间
  10. await next(); // 调用下一个middleware
  11. console.log('执行顺序 --- 5')
  12. const ms = new Date().getTime() - start; // 耗费时间
  13. console.log(`Time: ${ms}ms`); // 打印耗费时间
  14. });
  15. app.use(async (ctx, next) => {
  16. console.log('执行顺序 --- 3')
  17. await next();
  18. console.log('执行顺序 --- 4')
  19. ctx.response.type = 'text/html';
  20. ctx.response.body = '<h1>Hello, koa2!</h1>';
  21. });
  1. // koa 的洋葱模型,先由外至内,然后,由内传外
  2. console.log('执行顺序 --- 1')
  3. ...
  4. console.log('执行顺序 --- 3')
  5. ...
  6. console.log('执行顺序 --- 6')

koa-router

为了处理URL,引入 koa-router 这个middleware

koa-router 基本用例

  1. npm install koa-router
  1. const Koa = require('koa');
  2. // 注意require('koa-router')返回的是函数:
  3. const router = require('koa-router')();
  4. const app = new Koa();
  5. // log request URL:
  6. app.use(async (ctx, next) => {
  7. console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
  8. await next();
  9. });
  10. // add url-route:
  11. router.get('/hello/:name', async (ctx, next) => {
  12. var name = ctx.params.name;
  13. ctx.response.body = `<h1>Hello, ${name}!</h1>`;
  14. });
  15. router.get('/', async (ctx, next) => {
  16. ctx.response.body = '<h1>Index</h1>';
  17. });
  18. // add router middleware:
  19. app.use(router.routes());
  20. app.listen(3000);
  21. console.log('app started at port 3000...');

这样使用时,如果 URL 越来越多, app.js 会变的很冗余。

koa-bodyparser

post请求时,通常会发送一个 表单 或者 JSON 作为 request 的 body ,但无论是Node.js 提供的原始request对象,还是 koa 提供的 request 对象,都没有解析 request 的body 的功能。

koa-bodyparser 中间件的作用就是: 解析原始request请求,然后,将解析后的参数邦定到 ctx.request.body

  1. npm install koa-bodyparser
  1. ...
  2. const bodyParser = require('koa-bodyparser');
  3. ...
  4. // 然后再合适的位置加上
  5. app.use(bodyParser());
  6. ...

由于middleware的顺序很重要,这个koa-bodyparser必须在router之前被注册到app对象上。
**

模块发封装 koa-router 处理 URL

  1. url2-koa/
  2. |
  3. +- .vscode/
  4. | |
  5. | +- launch.json <-- VSCode 配置文件
  6. |
  7. +- controllers/
  8. | |
  9. | +- login.js <-- 处理login相关URL
  10. | |
  11. | +- users.js <-- 处理用户管理相关URL
  12. |
  13. +- app.js <-- 使用koajs
  14. |
  15. +- controller.js
  16. |
  17. +- package.json <-- 项目描述文件
  18. |
  19. +- node_modules/ <-- npm安装的所有依赖包

controllers / hello.js

  1. var fn_hello = async (ctx, next) => {
  2. var name = ctx.params.name;
  3. ctx.response.body = `<h1>Hello, ${name}!</h1>`;
  4. };
  5. module.exports = {
  6. 'GET /hello/:name': fn_hello
  7. };

controller.js

  1. const fs = require('fs');
  2. // add url-route in /controllers:
  3. function addMapping(router, mapping) {
  4. for (var url in mapping) {
  5. if (url.startsWith('GET ')) {
  6. var path = url.substring(4);
  7. router.get(path, mapping[url]);
  8. console.log(`register URL mapping: GET ${path}`);
  9. } else if (url.startsWith('POST ')) {
  10. var path = url.substring(5);
  11. router.post(path, mapping[url]);
  12. console.log(`register URL mapping: POST ${path}`);
  13. } else if (url.startsWith('PUT ')) {
  14. var path = url.substring(4);
  15. router.put(path, mapping[url]);
  16. console.log(`register URL mapping: PUT ${path}`);
  17. } else if (url.startsWith('DELETE ')) {
  18. var path = url.substring(7);
  19. router.del(path, mapping[url]);
  20. console.log(`register URL mapping: DELETE ${path}`);
  21. } else {
  22. console.log(`invalid URL: ${url}`);
  23. }
  24. }
  25. }
  26. /* router 为 koa-router 对象
  27. * dir 为 处理URL文件所在的文件夹
  28. * 该方法主要作用是 先通过 fs.readdirSync 读取 处理URL的文件, 然后循环 引用该文件,
  29. * 然后,将引用的文件 传递给 addMapping 方法,并通过此方法将处理逻辑交给 koa-router 中间件处理
  30. */
  31. function addControllers(router, dir) {
  32. fs.readdirSync(__dirname + '/' + dir).filter((f) => {
  33. return f.endsWith('.js');
  34. }).forEach((f) => {
  35. console.log(`process controller: ${f}...`);
  36. let mapping = require(__dirname + '/' + dir + '/' + f);
  37. addMapping(router, mapping);
  38. });
  39. }
  40. module.exports = function (dir) {
  41. let
  42. controllers_dir = dir || 'controllers',
  43. router = require('koa-router')(); // 调用 koa-router
  44. addControllers(router, controllers_dir);
  45. return router.routes();
  46. };

app.js

  1. const Koa = require('koa');
  2. const bodyParser = require('koa-bodyparser');
  3. const controller = require('./controller');
  4. const app = new Koa();
  5. // 打印请求日志信息
  6. app.use(async (ctx, next) => {
  7. console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
  8. await next();
  9. });
  10. // parse request body:
  11. app.use(bodyParser()); // 在 router 调用前注册到 app上
  12. // add controllers:
  13. app.use(controller());
  14. app.listen(3000);
  15. console.log('app started at port 3000...');

**—-> 廖雪峰 github demo(模块化封装 处理 URL功能)