• 了解Koa和创建路由实例


    Koa 介绍

    koa 是由 Express 原班人马打造的,一个基于 Node.js 平台的 Web 开发框架

    Express 是基于 ES5 的语法,随着新版 Node.js 开始支持 ES6 ,该团队重新编写诞生了 koa 1.0 ,而 koa2.0 则是更是超前的基于 ES7

    安装 koa2

    npm i koa
    

    创建 koa2 工程

    // 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
    const Koa = require('koa');
    
    // 创建一个Koa对象表示web app本身:
    const app = new Koa();
    
    app.use( ... )
    
    // 在端口3000监听:
    app.listen(3000);
    app.use([path,] function [, function…])

    在 path 上安装中间件,每当请求的路径的基路径和该path匹配时,都会导致该中间件函数被执行,如果 path 没有被设定,那么默认为 /

    app.use('/admin', function(req, res) {
       console.log(req.originalUrl); // '/admin/new'
    	console.log(req.baseUrl); // '/admin'
    	console.log(req.path); // '/new'
    });
    app.use(async (ctx, next) => {
        await next(); // 处理下一个异步函数    
        ctx.response.type = 'text/html' // 设置 response 的 Content-Type
        ctx.response.body = '<h1>Hello, koa2!</h1>' // 设置 response 的内容
    })
    

    由 async 标记的函数称为异步函数,在异步函数中,可以用 await 调用另一个异步函数,这两个关键字将在 ES7 中引入(用法看上去类似 Promise)

    上述代码中,参数 ctx 是由 koa 传入的封装了 request 和 response 的变量,我们可以通过它访问 request 和 response, next 是 koa 传入的将要处理的下一个异步函数

    对于每一个 http 请求, koa 将调用通过 app.use() 注册的 async 函数,并传入 ctx 和 next 参数

    实例:

    const Koa=require('koa');
    const app=new Koa();
    app.use(async (ctx, next) => {
        console.log('第一1');
        await next(); // 调用下一个middleware
        console.log('第一2');
    });
    app.use(async (ctx, next) => {
        console.log('第二1');
        await next(); // 调用下一个middleware
        console.log('第二2');
    });
    app.use(async (ctx, next) => {
        console.log('第三1');
        await next();
        console.log('第三2');
    });
    app.listen(3000);
    
    // 打印结果如下:
    // 第一1
    // 第二1
    // 第三1
    // 第三2
    // 第二2
    // 第一2

    koa-router 和 koa-bodyparser

    koa-router 负责处理 URL 映射,通过它可以更便捷的对 URL 进行操作

    koa-router 使用

    const router = require('koa-router')(); // 引入 koa-router
    ……
    // add router middleware:
    app.use(router.routes());
    

    注意导入 koa-router 的语句最后的 () 是对函数调用

    通过使用 koa-router ,我们可以处理一些更复杂的 URL 操作,比如 GET 请求

    // log request URL:
    app.use(async (ctx, next) => {
        console.log(`<h1>Hello, ${name}!</h1>`);
        await next();
    });
    
    // add url-route:
    router.get('/hello/:name', async (ctx, next) => {
        var name = ctx.params.name; // 通过 ctx.params.name 可以获取 URL 带来的变量
        ctx.response.body = `<h1>Hello, ${name}!</h1>`;
    });

    处理 get 请求

    用 router.get('/path', async fn) 处理的是 get 请求

    处理 post 请求

    用 router.post('/path', async fn) 处理 post 请求

    需要注意,post 请求的数据,无法正确为客户端解析成正确的 request 的 body ,此时需要利用 koa-bodyparser 组件实现解析

    koa-bodyparser 使用

    const router = require('koa-router')(); // 引入 koa-router
    const bodyParser = require('koa-bodyparser');
    app.use(bodyParser()); // 在 router.routes 之前注入 bodyParser
    ……
    router.post('/path', async fn)
    ……
    // add router middleware:
    app.use(router.routes());
    app.listen(3000);
    

    注意 koa-bodyparser 必须在 router 之前被注册到 app 对象上

    路由实例

    提取路由

    为了使目录结构更为美观,可以将所有的 URL 处理函数都提取出来

    // index.js
    var fn_index = async (ctx, next) => { …… };
    var fn_signin = async (ctx, next) => { …… };
    module.exports = {
        'GET /': fn_index,
        'POST /signin': fn_signin
    };
    

    app.js 页面在获取上,廖雪峰的实例代码略显复杂,如下

    var fs = require('fs') // 引入 Node.js 核心模块 fs
    
    // 通过 fs.readdirSync 同步读取 /controllers 目录下的文件
    // 该源实例 index.js 存放于 /controllers 目录下
    var files = fs.readdirSync(__dirname + '/controllers');
    // 源实例注解:这里可以用sync是因为启动时只运行一次,不存在性能问题
    
    // 过滤该目录下所有 .js 后缀的文件
    var js_files = files.filter((f)=>{
        return f.endsWith('.js');
    });
    
    // 循环所有 .js 后缀的文件
    for (var f of js_files) {
        // 动态引入每一个 js 文件,此处并非真实引入
        let mapping = require(__dirname + '/controllers/' + f);
        for (var url in mapping) { // 此时的 mapping 为每一个 .js 文件的 exports 对象,循环该对象
            if (url.startsWith('GET ')) { // 如果对象键名 url 已 'GET ' 开头
                var path = url.substring(4); // 提取键名中的路径部分,此处是 '/'
                router.get(path, mapping[url]);
            } else if (url.startsWith('POST ')) { // 如果对象键名 url 已 'POST ' 开头
                var path = url.substring(5); // 提取键名中的路径部分,此处是 '/signin'
                router.post(path, mapping[url]);
            } else {
                // 无效的URL:
                console.log(`invalid URL: ${url}`);
            }
        }
    }
    fs.readdirSync(path[, options]) 同步版本的 fs.readdir() ,参数如下 path String | Buffer | URLoptions String | Objectencoding String 默认值 'utf8'withFileTypes Boolean 默认值 false返回 <string[]> | <Buffer[]>| <fs.Dirent[]>

    可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传给回调的文件名的字符编码。 如果 encoding 设置为 'buffer',则返回的文件名是 Buffer 对象。

    __dirname

    在每个 Node.js 模块中,除 require 、exports 等模块之外还都包含两个特殊成员

    __dirname 动态获取当前文件模块所属目录的绝对路径__filename 动态获取当前文件的绝对路径

    str.startsWith(searchString [, position])

    startsWith() 方法用来判断当前字符串是否是以另外一个给定的子字符串开头的,根据判断结果返回 true 或 false

    searchString 要搜索的子字符串position 在 str 中搜索 searchString 的开始位置,默认值为 0,也就是真正的字符串开头处

    endsWith()

    方法用于测试字符串是否以指定的后缀结束。如果参数表示的字符序列是此对象表示的字符序列的后缀,则返回 true,否则返回 false

    stringObject.substring(start,stop)

    substring() 方法用于提取字符串中介于两个指定下标之间的字符

    start 必需。一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置

    stop 可选。一个非负的整数,比要提取的子串的最后一个字符在 stringObject 中的位置多 1。

    如果省略该参数,那么返回的子串会一直到字符串的结尾

    电脑刺绣绣花厂 http://www.szhdn.com 广州品牌设计公司https://www.houdianzi.com

    精简入口文件(app.js)

    将以上代码复制一份,命名为 controller.js ,优化代码,如下

    var fs = require('fs') // 引入 Node.js 核心模块 fs
    const router = require('koa-router')(); // 引入 koa-router
    // 函数 addMapping 包含两个参数
    // router koa-router 实例
    // mapping 所有路由 url
    function addMapping(router, mapping) {
        for (var url in mapping) { // 此时的 mapping 为每一个 .js 文件的 exports 对象,循环该对象
            if (url.startsWith('GET ')) { // 如果对象键名 url 已 'GET ' 开头
                var path = url.substring(4); // 提取键名中的路径部分,此处是 '/'
                router.get(path, mapping[url]);
            } else if (url.startsWith('POST ')) { // 如果对象键名 url 已 'POST ' 开头
                var path = url.substring(5); // 提取键名中的路径部分,此处是 '/signin'
                router.post(path, mapping[url]);
            } else {
                console.log(`invalid URL: ${url}`);
            }
        }
    }
    function addControllers(router, dir) {
        // 通过 fs.readdirSync 同步读取 /controllers 目录下的文件
    	// 该源实例 index.js 存放于 /controllers 目录下
        var files = fs.readdirSync(__dirname + '/' + dir);
        // 过滤该目录下所有 .js 后缀的文件
        var js_files = files.filter((f) => {
            return f.endsWith('.js');
        });
        // 循环所有 .js 后缀的文件
        for (var f of js_files) {
            // 动态引入每一个 js 文件,此处并非真实引入
            let mapping = require(__dirname + '/' + dir + '/' + f);
            // 调用 addMapping 函数,并将
            addMapping(router, mapping);
        }
    }
    module.exports = function (dir) {
        let controllers_dir = dir || 'controllers', // 如果不传参数,扫描目录默认为'controllers'
            router = require('koa-router')(); // 动态引入 koa-router 组件
        addControllers(router, controllers_dir);
        // 实参 router 为实例化 router
        // 实参 controllers_dir 为路径
        return router.routes(); // add router middleware
    };
    

    这样一来,我们在 app.js 的代码又简化了

    // 导入 controller middleware:
    const controller = require('./controller');
    
    // 使用 middleware:
    app.use(controller());
  • 相关阅读:
    WPF Path使用Geometry数据
    WPF Uri反射加载XAML
    T4模板生成数据库实体DB First
    Unsatisfied dependency expressed through method 'shirFilter' parameter 0 异常排查
    SpringBoot集成多数据源
    SpringBoot整合Flyway数据库版本管理
    阿里云服务器Docket安装RabbitMQ 3.8.12
    Docker 部署阿里云RocketMQ 4.5.1
    SpringBoot 整合EasyExcel 获取动态Excel列名
    SpringBoot 开发提速神器 Lombok+MybatisPlus+SwaggerUI
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/13826030.html
Copyright © 2020-2023  润新知