koa2_koa2 重定向 - CSDN
精华内容
参与话题
  • koa2全了解

    千次阅读 2019-04-01 16:41:35
    1nodejs必须&...koa2与express相比就是能避免异步嵌套 //0必须先安装完nodejs后才能 //1创建目录夹 //2项目初始化 npm init //3项目安装koa npm install --save koa //4第一个helloworld const

    1nodejs必须>7.6才完全支持koa2
    koa2与express相比就是能避免异步嵌套

    //0必须先安装完nodejs后才能
    //1创建目录夹
    
    //2项目初始化
    npm init
    
    //3项目安装koa
    npm install --save koa
    
    //4第一个helloworld
    const koa = require("koa");
    
    let app = new koa();
    
    app.use(async (ctx)=>{
        ctx.body = "你好";
    });
    
    app.listen(3000);
    

    async用于声明一个function是异步的
    await是等待异步方法执行完成,并且必须用在异步方法里面才不报错
    nodejs里面所有的方法都是异步,所以await可以直接用在方法内调用方法
    区别:
    promise代表一个对象是异步的(对应then),async代表一个方法是异步的(对应await)
    //await阻塞的功能,可以把异步改成同步

    async function getData() {
        return "这是一个异步方法";
    }
    console.log(getData());//Promise { '这是一个异步方法' }
    
    
    //await是等待异步方法执行完成,并且必须用在异步方法里面才不报错
    async function getData() {
        return "这是一个数据";
    }
    async function getData2() {
       let p = await getData();
       console.log(p);
    }
    getData2();
    
    
    //await阻塞功能
    async function getData() {
        console.log(2);
        return "这是一个数据";
    }
    async function getData2() {
        console.log(1);
       let p = await getData();
       console.log(p);
       console.log(3);
    }
    getData2();//1,2,3 await阻塞功能
    
    //await也可获取Promise的异步返回结果
    function getData() {
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                let name = "张三";
                resolve(name);
            },1000)
        });
    }
    async function test(){
        var data = await getData();
        console.log(data);
    }
    test();
    
    //安装koa-router,koa的路由器
    npm install koa-router --save
    
    //1引入模块,类的命名一般首字母大写
     const Koa = require("koa");
    // const Router = require('koa-router');
    //2实例化对象
     let app = new Koa();
    // let router = new Router();
    
    //一步引入并实例化路由
    let router = require('koa-router')();
    
    
    //3ctx表示上下文content,包含了request和response等信息
    router.get('/',async (ctx)=>{
        ctx.body="首页"; //返回数据 相当于原生里面的res.writeHead() res.end();
    }).get('/news',async (ctx)=>{
        ctx.body="新闻页面";
    })
    
    //4配置路由,必须加
    app
        .use(router.routes()) //配置路由
        .use(router.allowedMethods()); //建议配置:作用:可以根据ctx.status设置response响应头
    
    //5设置监听端口
    app.listen(3000);
    
    //1引入模块,类的命名一般首字母大写
     const Koa = require("koa");
    // const Router = require('koa-router');
    //2实例化对象
     let app = new Koa();
    // let router = new Router();
    
    //一步引入并实例化路由
    let router = require('koa-router')();
    
    
    //3ctx表示上下文content,包含了request和response等信息
    router.get('/',async (ctx)=>{
        ctx.body="首页"; //返回数据 相当于原生里面的res.writeHead() res.end();
    }).get('/news',async (ctx)=>{
        ctx.body="新闻页面";
    }).get('/newscontent/:aid',async (ctx)=>{
    	//动态路由也可以传多个值,但必须全匹配才正常返回
        //动态路由http://localhost:3000/newscontent/xxx   console.log(ctx.params);获得{ aid: 'xxx' }
    
        //http://localhost:3000/newscontent?adi=123
        // 在 koa2 中 GET 传值通过 request 接收,但是接收的方法有两种:query 和 querystring。
        // query:返回的是格式化好的参数对象。
        // querystring:返回的是请求字符串。
        // console.log(ctx.query); //{ adi: '123' }获取的是对象,常用
        // console.log(ctx.querystring); //adi=123 获取的是字符串
        // console.log(ctx.request); //获取全部信息
    
        console.log(ctx.params);
    
        ctx.body="新闻详情页面";
    })
    
    //4配置路由,必须加
    app
        .use(router.routes()) //配置路由
        .use(router.allowedMethods()); //建议配置:作用:可以根据ctx.status设置response响应头
    
    //5设置监听端口
    app.listen(3000);
    

    koa的4种中间件:
    应用级中间件
    路由级中间件
    错误处理中间件
    第三方中间件
    在这里插入图片描述

    //1引入模块,类的命名一般首字母大写
     const Koa = require("koa");
    //2实例化对象
     let app = new Koa();
    //一步引入并实例化路由
     let router = require('koa-router')();
    
    
    
    //3ctx表示上下文content,包含了request和response等信息
    router.get('/',async (ctx)=>{
        ctx.body="首页"; //返回数据 相当于原生里面的res.writeHead() res.end();
    }).get('/news',async (ctx,next)=>{
        //路由级中间件next
        ctx.body="新闻页面";
        await next();
    }).get('/newscontent/:aid',async (ctx)=>{
        ctx.body="新闻详情页面";
    })
    
    router.get('/news',async (ctx)=>{
        console.log("新闻页面");
    })
    
    //匹配所有路由,如果不写next,这个路由被匹配到了,就不会继续向下匹配(应用级中间件),app.use最先执行
    app.use(async (ctx,next)=>{
        console.log(new Date());
        console.log(ctx);
        await next();
    
        //错误处理中间件
        if(ctx.status==404){
            ctx.status = 404;
            ctx.body = "404页面";
        } else {
          console.log(ctx.url);
        }
    });
    
    //4配置路由,必须加
    app
        .use(router.routes()) //配置路由
        .use(router.allowedMethods()); //建议配置:作用:可以根据ctx.status设置response响应头
    
    //5设置监听端口
    app.listen(3000);
    

    //5 ejs模板

    //安装模板引擎
    npm install koa-views --save
    //安装ejs
    npm install ejs --save
    //配置全局变量,(放在一个中间件里),注意➕await next();
    ctx.state.info="张三"
    
    //案例
    const Koa = require("koa");
    const router = require('koa-router')();
    const views = require('koa-views');
    
    let app = new Koa();
    
    app.use(views('views',{
        extension:'ejs'
    }));
    
    router.get('/',async (ctx)=>{
        await ctx.render('index');
    })
    router.post('/add',async (ctx)=>{
        console.log(ctx);
    })
    
    app.use(router.routes());
    app.use(router.allowedMethods());
    app.listen(3000);
    

    6获取post请求的数据中间间 koa-bodyparser

    //安装
    npm install --save koa-bodyparser
    //引入
    const bodyParser = require('koa-bodyparser');
    //使用
    app.use(bodyParser());
    //中间件中获取post数据
    ctx.request.body
    

    7静态资源中间件

    //安装
    npm install koa-static --save
    //引入
    const static = require('koa-static');
    //使用(可配置多个)
    app.use(static('static'));
    或app.use(static(__dirname+'static'));
    
    //ejs文件引入也只需写static文件夹后面的目录即可
    <link rel="stylesheet" href="css/index.css">
    

    8koa的cookie,(cookie无需安装即可使用)

    1 HTTP 是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页 面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问,都是没有任何关系的。

    2cookie 是存储于访问者的计算机中的变量。可以让我们用同一个浏览器访问同一个域名的时候共享数据。

    //koa设置cookies
    ctx.cookies.set(name, value, [options])
    //koa获取cookies
    ctx.cookies.get('name');
    //正常使用
    ctx.cookies.set('userInfo',userInfo,{
            maxAge:60*1000*60,
            httpOnly:false  //只服务器端和客户端(js)都可以访问
        });
        
    //需要转string类型存储,get时再转json类型
    router.get('/showinfo',async (ctx)=>{
        // let userInfo = ctx.cookies.get('userInfo');
        // ctx.body = userInfo;
        ctx.body = JSON.parse(ctx.cookies.get('userInfo')).username;
    })
    router.post('/add',async (ctx)=>{
        let userInfo = JSON.stringify(ctx.request.body);
        ctx.cookies.set('userInfo',userInfo,{
            maxAge:60*1000*60
        });
        ctx.body=userInfo;
    })
    //koa的cookie存储中文bug-转base64进行存储,取出再转中文
    let name = new Buffer('刘晓飞').toString('base64');// 转换成 base64
    ctx.cookies.set('name',name);
    //取
    console.log(new Buffer(ctx.cookies.get('name'), 'base64').toString());
    

    options可能的值
    在这里插入图片描述

    9session

    //安装
    npm install koa-session --save
    //引入
    const sesstion = require('koa-session');
    //配置
    app.keys = ['some secret hurr'];//cookie签名,不管
    const CONFIG = {
        key: 'koa:sess', //cookie的key,不管
        maxAge: 86400000, //cookie过期时间,毫秒 [需要修改]
        autoCommit: true,
        overwrite: true, //没效果,不管
        httpOnly: true, //true表示只有服务器端可获取cookie
        signed: true, //签名,默认
        rolling: false, //在每次请求时强行设置cookie,这将重置cookie过期时间(默认:false)
        renew: true, //快过期是否重新设置cookie,一般是true  [需要修改]
    };
    app.use(session(CONFIG, app));
    
    //使用
    设置值 ctx.session.username = "张三";
    获取值 ctx.session.username
    

    Cookie 和 Session 区别 1、cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
    2、cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗 考虑到安全应当使用 session。
    3、session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能 考虑到减轻服务器性能方面,应当使用 COOKIE。
    4、单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。

    10The yield keyword is used to pause and resume a generator function.

    Generator函数的最大用处就是用来生成一个遍历器。

    不过它是一个函数,所以和普通的函数有点区别,因此在声明函数的时候,要在function和函数名之间加一个*号:
    function *foo() {}

    yield也必须在Generator函数中才有意义

    // yield这个关键字是用来暂停和恢复一个遍历器函数(的运行)的。
    而yield告诉程序当前的状态值,而且你运行到这里给我暂停一下。

    就用上面的代码来说好了。Generator函数的特点就是“它是一个遍历器”,你不让它动,它绝对不会动。

    函数只能返回一次,所以必须返回一个Array。但是,如果换成generator,就可以一次返回一个数,不断返回多次。
    因为generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能。

    generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。
    https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143450083887673122b45a4414333ac366c3c935125e7000

    var foo = function *() {
    		  var x = 1;
    		  var y =  yield (x + 1);
    		  var z = yield (x + y);
    		  return z;
    		}()
    		var a = foo.next(); // 第一次执行next()不可以传参,a.value你应该知道,就2(x = 1, x + 1 = 2)。
    		console.log(a); //2
    		var b = foo.next(3); //第二次执行foo.next(3)的时候,yield x + 1这一大坨就是3,所以y = 3!“xx老谋”。所以,b.value的结果就是4 (x = 1,y = 3, x + y = 4).
    		console.log(b); //4
    		var c = foo.next(4);
    		console.log(c); //4
    

    总结一下
    写了这么多,总结一下yield,实际上:

    只能在Generator函数内部使用
    运行.next(),遇到一个yield命令,就暂停
    .next()的返回值表示一个状态{value,done}
    再运行.next(),从之前遇到的那个yield [表达式]处(后)继续恢复运行
    当.next()传参的时候,yield [表达式]整个被替换为传入的参数。

    最后,说一下for...of是怎么运行的。
    
    function *foo() {
      yield 1;
      yield 2;
      yield 3;
      return;
    }
    for(let v of foo()) {
      console.log(v);
    }
    for...of在遍历foo()返回的结果时,每遇到一个yield,就把yield后面表达式的结果作为of前面的v的值进行赋值(next()返回值的value字段)。
    
    展开全文
  • koa2的学习

    2019-03-23 08:28:13
    koa2.x的学习 安装和搭建 安装 ## 初始化package.json 初始化pa npm init # 安装koa2 npm install koa 搭建 // 由于koa2是基于async/await操作中间件,目前node.js 7.x的harmony模式下才能...

    koa2.x的学习

    安装和搭建

    安装

    
        ## 初始化package.json 初始化pa 
        npm init
    
        # 安装koa2 
        npm install koa
    

    搭建

    
    // 由于koa2是基于async/await操作中间件,目前node.js 7.x的harmony模式下才能使用,所以启动的时的脚本如下:
    
    
    const koa = require('koa')
    const app = new koa()
    
    
    //express 自带路由
    //koa需要自己配置  就是中间件
    
    
    
    //express 写法
    // app.use((req, res) => {
    //     res.send('返回数据');
    // })
    
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';
    })
    
    app.listen(8000);
    
    

    访问: http:localhost:8000 即可出现hello world

    es6基础

    • let 块级作用域
    • const 是常量
    • 模板字符串 console.log(${name}的年龄${age}); 大话西游2的年龄15
    • 属性的简写 let name=“123” let app ={ name: name } ==>简写 let name=“123” let app ={ name }
    • 方法的简写
    • 箭头函数 箭头指向上下文
    • promise async await

    Router

    router是由一个URI和一个特定的HTTP方法(get,post)等组成,涉及到应用如何响应客户端对某个网站节点的访问。
    通俗的说根据不同的URL加载不同的页面

    express中自带路由, koa2中需要自己安装: npm install koa-router

    koa-router

    详情链接

    例子1:

    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    //实例化
    const app = new Koa()
    const router = new Router()
    
    
    
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
        
        ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    }).get('/news', async (ctx) =>{
        ctx.body = 'thia is news page.'
    })
    
    
    app
      .use(router.routes()) //启动路由
      .use(router.allowedMethods());   // 使用在router.routes()之后,所有的路由中间件最后调用,此时根据ctx.status设置response的响应头
    
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';  //显示在浏览器中
    })
    
    app.listen(8000);
    
    
    

    从ctx中读取get传值

    通过request接收,但是接收的方法有两种query和querystring
    query: 返回的格式化好的参数对象
    querystring: 返回的是请求字符串
    
    //访问  http://localhost:8000/newscontent?username=123&password=123
        方式1:
            console.log(ctx.query) //  { username: '123', password: '123' } 获取的是对象 用的最多的方式
            console.log(ctx.querystring) //  username=123&password=123  是一个字符串
            console.log(cts.url) // /newscontent?username=123&password=123
        方式2:
            console.log(ctx.request.query) //{ username: '123', password: '123' }
            console.log(ctx.request.querystring) //  username=123&password=123  是一个字符串
            console.log(cts.request.url) // /newscontent?username=123&password=123
    
    
    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    //实例化
    const app = new Koa()
    const router = new Router()
    
    
    
    
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
       
       ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    }).get('/news', async (ctx) =>{
       ctx.body = 'thia is news page.'
    }).get('/newscontent', async (ctx) =>{
       // 从ctx中读取get传值
       /*
           通过request接收,但是接收的方法有两种query和querystring
           query: 返回的格式化好的参数对象
           querystring: 返回的是请求字符串
       */
    
       //访问  http://localhost:8000/newscontent?username=123&password=123
       console.log(ctx.query) //  { username: '123', password: '123' } 获取的是对象 用的最多的方式
    
       console.log(ctx.querystring) //  username=123&password=123  是一个字符串
    
       console.log(cts.url) // /newscontent?username=123&password=123
    
       // 从ctx里面的request里面获取get传值
       // console.log(ctx.request)
       /*
       { method: 'GET',
       url: '/newscontent?username=123&password=123',
       header:
      { host: 
        connection:  
        'upgrade-insecure-requests': 
        'user-agent':
         accept:
        'accept-encoding': 
        'accept-language':  
         cookie:
         ....
       */
    
       console.log(ctx.request.query) //{ username: '123', password: '123' }
       console.log(ctx.request.querystring) //  username=123&password=123  是一个字符串
       console.log(cts.request.url) // /newscontent?username=123&password=123
    
    })
    
    
    app
     .use(router.routes()) //启动路由
     .use(router.allowedMethods());
    
    //中间件
    app.use(async (ctx) => {
       ctx.body = 'hello world';
    })
    
    app.listen(8000);
    
    
    

    动态路由的使用并获取参数

    当url为//http://localhost:8000/newscontent/123,对应的代码为
    router.get('/newscontent/:aid', async (ctx) =>{
        console.log(ctx.params) //{ aid: '123' }
    
    })
    通过params获取参数
    

    例子:

    
    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    //实例化
    const app = new Koa()
    const router = new Router()
    
    /**
     * 动态路由
     */
    
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
        
        ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    }).get('/news', async (ctx) =>{
        ctx.body = 'thia is news page.'
    })
    
    // 一个
    router.get('/newscontent/:aid', async (ctx) =>{
        
        //http://localhost:8000/newscontent/123
        console.log(ctx.params) //{ aid: '123' }
    
    })
    
    //多个
    router.get('/newscontent/:aid/:name', async (ctx) =>{
        
        //http://localhost:8000/newscontent/123
        console.log(ctx.params) //{ aid: '123', name: 'zhang' }
    
    })
    
    
    app
      .use(router.routes()) //启动路由
      .use(router.allowedMethods());
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';
    })
    
    app.listen(8000);
    
    
    

    中间件

    路由官方地址:https://www.npmjs.com/package/koa-router
    就是匹配路由之前匹配路由完成做的一系列的操作

    中间件的功能:

    • 执行任何代码
    • 修改请求和响应对象
    • 终结请求-响应循环
    • 调用堆栈中下一个中间件

    koa应用如下几种中间件:

    • 应用级中间件
    • 路由级中间件
    • 错误处理中间件
    • 第三方中间件

    应用级中间件

    匹配路由之前做的操作
    如果不写next, 这个路由被匹配到了就不会继续了
    next() 当前路由匹配完成以后继续向下匹配
    app.use(async (ctx)=>{}) //匹配任意路由的中间件,且在路由函数之前执行

    
    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    const app = new Koa()
    const router = new Router()
    
    /*
    // 匹配任何路由  
    app.use(async (ctx) =>{
       
    })
    
    */
    
    // 匹配路由之前打印日期
    //http://localhost:8000/xxx
    //http://localhost:8000/
    app.use(async (ctx, next) =>{
        console.log(new Date())
        await next()
    })
    
    
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
        
        ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    })
    
    router.get('/news', async (ctx) =>{
        ctx.body = 'thia is news page.'
    })
    router.get('/news1', async (ctx) =>{
        ctx.body = 'thia is news page.'
    })
     
    app
      .use(router.routes()) //启动路由
      .use(router.allowedMethods());
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';
    })
    
    app.listen(8000);
    
    
    

    路由级中间件

    匹配到news路由以后继续向下匹配路由

    
    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    const app = new Koa()
    const router = new Router()
    
    /**
     * 路由级中间件  匹配到news路由以后继续向下匹配路由
     * 
     * 例如 两个同样的router 如下
     * 
     * http://localhost:8000/news
     * 
     *  this is news page. 
     **/
    
    
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
        
        ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    })
    
    // http://localhost:8000/news
    router.get('/news', async (ctx, next) =>{
       console.log('this is news page.')
    
       await next()
    })
    
    router.get('/news', async (ctx) =>{
        ctx.body = ' this is news page. '
    })
    
    
    app
      .use(router.routes()) //启动路由
      .use(router.allowedMethods());
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';
    })
    
    app.listen(8000);
    
    • 错误处理中间件

    这里说下use与router的顺序问题,

    
    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    const app = new Koa()
    const router = new Router()
    
    /**
     * 路由级中间件  匹配到news路由以后继续向下匹配路由
     * 
     * 
     * 这个第一个中间件01
     * 新闻页面02
     * 打印url->03
     * /news
     * 
     * 
     * 
     * 执行过程 http://localhost:8000/news  => console.log('这个第一个中间件01'); ==>执行 await next() ==>寻找对应的路由 ==>console.log('新闻页面02')
     * 再返回到 app.use  接着执行下面的代码  ==> console.log('打印url->03'); ...
     * 
     * 洋葱模式
     * 
     * 
     * 
    **/
    app.use(async (ctx, next)=>{
        
        console.log('这个第一个中间件01');
    
        await next();
    
        if(ctx.status === 404) {
            ctx.status = 404;
            ctx.body = 'this is 404 page';
        }else {
            console.log('打印url->03');
            console.log(ctx.url)
        }
    
    })
     
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
        
        ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    })
    
    // http://localhost:8000/news
    router.get('/news', async (ctx, next) =>{
       console.log('新闻页面02')
    
       await next();
       
    })
    
    router.get('/news', async (ctx) =>{
        ctx.body = ' this is news page. '
    })
     
    app
      .use(router.routes()) //启动路由
      .use(router.allowedMethods());
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';
    })
    
    app.listen(8000);
    

    执行的流程

    
    const Koa = require('koa')
    const Router = require('koa-router'); // 注意引入方式
    
    const app = new Koa()
    const router = new Router()
    
    /**
     * 路由级中间件  匹配到news路由以后继续向下匹配路由
     * 
     * 
     * 这个第一个中间件01
     * 新闻页面02
     * 打印url->03
     * /news
     * 
     * 
     * 
     * 执行过程 http://localhost:8000/news  
     *              这个第一个中间件01
                    这个第二个中间件02
                    匹配news路由03
                    返回到这里03
                    返回到这里04
     * 洋葱模式
    **/
    
    app.use(async (ctx, next)=>{
        
        console.log('这个第一个中间件01');
        next();
        console.log('返回到这里04');
    })
     
    
    app.use(async (ctx, next)=>{
        
        console.log('这个第二个中间件02');
        next();
        console.log('返回到这里03');
    })
    
    
    //配置路由
    // ctx 上下文  包含request和response等信息
    router.get('/', async (ctx)=> {
        
        ctx.body = '首页'  /*返回数据 相当于 res.writeHead() res.end() */
    })
    
    // http://localhost:8000/news
    router.get('/news', async (ctx) =>{
       console.log('匹配news路由03  ')
        
       ctx.body = '新闻'
       
    })
    
    app
      .use(router.routes()) //启动路由
      .use(router.allowedMethods());
    
    //中间件
    app.use(async (ctx) => {
        ctx.body = 'hello world';
    })
    
    app.listen(8000);
    
    
    

    ejs模板引擎

    官网文档: https://www.npmjs.com/package/koa-views

    1. 安装: npm install koa-views
      npm install ejs
    2. 引入 koa-views 配置中间件
      方式1:
            const views = require('koa-views');
            app.use(views('views', { map: {html: 'ejs' }})); // //这样配置也可以  注意如果这样配置的话 模板的后缀名是.html
    
    方式2:
    
            app.use(views('views',{
                extension:'ejs'  /*应用ejs模板引擎*/
            }))
    
    1. 使用:
      router.get(’/add’,async (ctx)=>{
      let title = ‘hello koa2’
      await ctx.render(index’,{
      title
      })
      })

    4、Ejs 引入模板

    <%- include header.ejs %>
    

    5、Ejs 绑定数据

    <%=h%>
    

    6、Ejs 绑定 html 数据

    <%-h%>
    

    7、Ejs 模板判断语句

        <% if(true){ %>
        <div>true</div>
        <%} else{ %>
        <div>false</div>
        <%} %>
    

    8、Ejs 模板中循环数据

        <%for(var i=0;i<list.length;i++) { %><li><%=list[i] %></li>
        <%}%>
    
    1. 公共数据

    注意:我们需要在每一个路由的render里面都要渲染一个公共的数据

    公共的数据放在这个里面,这样的话在模板的任何地方都可以使用
    
    //写一个中间件配置公共的信息
    app.use(async (ctx,next)=>{
    
        ctx.state.userinfo='张三';
    
        await next();/*继续向下匹配路由*/
    })
    

    待完善。。。。。
    https://www.itying.com/koa/article-index-id-90.html

    展开全文
  • 使用Koa2搭建web项目

    万次阅读 2017-09-15 09:04:37
    使用koa2搭建web项目,包含项目架构设计,实现请求获取数据以及保存数据,mysql数据库连接池请求处理

    使用Koa2搭建web项目

        随着Node.js的日益火热,各种框架开始层出不穷的涌现出来,Node.js也开始逐渐的被应用到处理服务端请求的场景中。搭建Web项目的框架也随之开始出现——express、koa、koa2、egg等,当然要了解其好坏还是要自己去啃源码的。本文将不会涉及到源码,只是带领初学者简单了解下Koa2的基本使用,欢迎大家在评论中互相交流学习。


        注意:koa2使用了ES7的语法,所以使用时请升级Node版本到最新。了解更详细的源码信息可以到git上的koajs/koa去了解


    1. 项目目录结构

    Koa2项目目录结构


    2. 代码逻辑解析


    2.1. 包结构文件

    [package.json]

    {
      "name": "weixin-node-koa",
      "version": "1.0.0",
      "description": "node.js with koa2",
      "private": true,
      "dependencies": {
        "koa": "^2.0.0",
        "koa-router": "^7.0.0",
        "mysql":"2.13.0"
      },
      "scripts": {
        "start": "node app.js"
      },
      "engines": {
        "node": ">=6.0.0"
      },
      "author": "Fly",
      "license": "CENTERM"
    }

    2.2. 启动入口文件

    [app.js]

    const Koa = require('koa');
    const app = new Koa();
    const router2controller = require('./app/router2controller.js');
    const config = require('./config/config.local.js');
    
    app.use(router2controller());
    app.listen(config.port);
    console.log("Server started and listen on port " + config.port);

    如果请求的报文体是XML格式,可以添加下面的代码自动解析报文(注意引用koa-xxx的版本要与koa2对应

    const Koa = require('koa');
    const app = new Koa();
    const router2controller = require('./app/router2controller.js');
    const config = require('./config/config.local.js');
    
    //start接收到的xml数据请求单独解析存储
    const xmlParser = require('koa-xml-body');
    app.use(xmlParser()).use((ctx,next) => {
        ctx.data = ctx.request.body;
        return next();
    });
    //end
    
    app.use(router2controller());
    app.listen(config.port);
    console.log("Server started and listen on port " + config.port);

        从代码看到引入了一个router2controller.js的文件,这个文件是完成前端请求到具体处理方法的路由过程


    2.3. 路由器文件

    [router2controller.js]

    该类将会自动扫描controller文件夹中的文件来加载请求映射,不需要挨个请求单独配置

    • koa-router原生提供方法如下:
    router
      .get('/', async (ctx,next) => {
        this.body = 'Hello World!';
      })
      .post('/users', async (ctx,next) => {
        //TODO
      })
      .put('/users/:id', async (ctx,next) => {
        //TODO
      })
      .del('/users/:id', async (ctx,next) => {
        //TODO
      });
    • 自动扫描controller包实现方法如下
    const fs = require('fs');
    const router = require('koa-router')();
    
    function addMapping(router, mapping) {
        for (var url in mapping) {
            if (url.startsWith('GET ')) {
                var path = url.substring(4);
                router.get(path, mapping[url]);
                console.log(`register URL mapping: GET ${path}`);
            } else if (url.startsWith('POST ')) {
                var path = url.substring(5);
                router.post(path, mapping[url]);
                console.log(`register URL mapping: POST ${path}`);
            } else if (url.startsWith('PUT ')) {
                var path = url.substring(4);
                router.put(path, mapping[url]);
                console.log(`register URL mapping: PUT ${path}`);
            } else if (url.startsWith('DELETE ')) {
                var path = url.substring(7);
                router.del(path, mapping[url]);
                console.log(`register URL mapping: DELETE ${path}`);
            } else {
                console.log(`invalid URL: ${url}`);
            }
        }
    }
    
    function addControllers(router, dir) {
        fs.readdirSync(__dirname + '/' + dir).filter((f) => {
            return f.endsWith('.js');
        }).forEach((f) => {
            console.log(`process controller: ${f}...`);
            let mapping = require(__dirname + '/' + dir + '/' + f);
            addMapping(router, mapping);
        });
    }
    
    module.exports = function (dir) {
        var controllersDir = dir || 'controller';
        addControllers(router, controllersDir);
        return router.routes();
    };

    2.4. 控制器

    [userController.js]

    ***Controller.js是用来处理具体请求信息以及返回数据的,userController.js中处理了GET请求获取用户信息,POST请求保存用户信息

    const userService = require('./../service/userService.js');
    
    var getUserinfo = (ctx, next) => {
        let query = ctx.query;
        let userId = query.id;
        let userInfo = userService.getUserById(userId);
    
        let html = '<html><body>'
            + '<div> userinfo:&nbsp;' + userInfo + '</div>'
            + '</body></html>';
        ctx.response.type ='text/html';
        ctx.response.body = html;
    };
    
    var saveUserinfo = (ctx, next) => {
        const requestString = ctx.data;
        //TODO数据处理
        Console.log(requestString);
    };
    
    module.exports = {
        'GET /getUserinfo': getUserinfo,
        'POST /saveUserinfo': saveUserinfo
    };

    2.5. 数据处理

    [userService.js]

    处理封装从***Dao.js获取到的数据返回给Controller

    const userDao = require('./../dao/userDao.js');
    
    var getUserById = async (userId) => {
        var users = userDao.getUserById(userId);
        var responseContent = '';
        for(let user of users) {
            reaponseContent += '姓名:' + user.name + '&nbsp;|';
            reaponseContent += '年龄:' + user.age + '&nbsp;|';
            reaponseContent += '身高:' + user.height + '<br />';
        }
        return responseContent;
    }
    
    module.exports = {
        getUserById : getUserById
    };

    2.6. 数据获取

    [userDao.js]

    通过请求传入参数来获取user数据

    const mysql = require('./../utils/mysqlUtil.js');
    
    var getUserById = async (userId) => {
        let mysqlOptions = {
            sql : 'select * from table_user where user_id = ?',
            args : [userId]
        };
    
        var users = await mysql.execQuery(mysqlOptions);
        if(users.length == 0) {
            return null;
        } else {
            return users;
        }
    };
    
    module.exports = {
        getUserById : getUserById
    };

    2.7. 数据库操作

    [mysqlUtil.js]

    包含了数据库连接池控制,连接建立、释放管理,执行Dao发起的数据库操作请求

    const mysql = require('mysql');
    const config = require('./../../config/config.local.js');
    
    var connectionPool = mysql.createPool({
        'host' : config.database.host,
        'port':config.database.port,
        'user' : config.database.user,
        'password' : config.database.password,
        'database' : config.database.database,
        'charset': config.database.charset,
        'connectionLimit': config.database.connectionLimit,
        'supportBigNumbers': true,
        'bigNumberStrings': true
    });
    
    var release = connection => {
        connection.end(function(error) {
            if(error) {
                console.log('Connection closed failed.');
            } else {
                console.log('Connection closed succeeded.');
            }
        });
    };
    
    var execQuery = sqlOptions => {
        var results = new Promise((resolve, reject) => {
                connectionPool.getConnection((error,connection) => {
                if(error) {
                    console.log("Get connection from mysql pool failed !");
                    throw error;
                }
    
                var sql = sqlOptions['sql'];
                var args = sqlOptions['args'];
    
                if(!args) {
                    var query = connection.query(sql, (error, results) => {
                        if(error) {
                            console.log('Execute query error !');
                            throw error;
                        }
    
                        resolve(results);
                    });
                } else {
                    var query = connection.query(sql, args, function(error, results) {
                        if(error) {
                            console.log('Execute query error !');
                            throw error;
                        }
    
                        resolve(results);
                    });
                }
    
                connection.release(function(error) {
                    if(error) {
                        console.log('Mysql connection close failed !');
                        throw error;
                    }
                });
            });
        }).then(function (chunk) {
            return chunk;
        });
    
        return results;
    };
    
    module.exports = {
        release : release,
        execQuery : execQuery
    }
    展开全文
  • koa2深入浅出

    2018-12-17 16:23:56
    koa2基础知识分享 koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套, 并极大地提升...

    koa2基础知识分享

    koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套, 并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件, 它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。

    安装

    Koa 依赖 node v7.6.0 或 ES2015及更高版本和 async 方法支持.
    你可以使用自己喜欢的版本管理器快速安装支持的 node 版本:

    $ nvm install 8
    $ npm i koa
    

    Hello world

    • nodejs原生
    const http = require('http');
    
    const hostname = '127.0.0.1';
    const port = 3000;
    
    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello World\n');
    });
    
    server.listen(port, hostname, () => {
      console.log(`Server running at http://${hostname}:${port}/`);
    });
    
    • koa2
    const  Koa = require("koa");
    const app = new Koa();
    
    function httpServer(ctx){
        ctx.body = "hello world";
    }
    app.use(httpServer);
    app.listen(3000);
    

    中间件(洋葱圈)

    • resquest --> response 之间发生
      avatar

    koa 中间件的机制 – 洋葱圈

    中间件A --> 中间件B --> 中间件C --> 中间件B --> 中间件A 响应结果

    koa2中间件的实现原理(use next [async,await] listen)
    next();

    1. 首先看 use ,就是push一个函数到 this.middleware
      [fn1,fn2,fn3]

    2. 再看listen, 方法里面 http.createServer(this.callBack), this.callBack返回的是 function(req,res){…}的函数
      ,连起来就是 http.createServer(function(req,res){…})

    3. 最后看callback里面的核心方法, compose(this.middleware) 返回一个promise,处理完毕后再执行 handleResponse

    这三个连起来,就是每次请求的时候,先进入callback, compose中间件,执行完毕后,接着处理请求。那剩下的重点变为 compose

    callback --> compose

    compose 核心的核心就是[dispatch], dispatch会根据 middleware 的长度,依次执行。

    if (i === middleware.length) fn = next
          if (!fn) return Promise.resolve()
    
    return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));       
    

    compose官网实现逻辑

    'use strict'
    
    /**
     * Expose compositor.
     */
    
    module.exports = compose
    
    /**
     * Compose `middleware` returning
     * a fully valid middleware comprised
     * of all those which are passed.
     *
     * @param {Array} middleware
     * @return {Function}
     * @api public
     */
    
    function compose (middleware) {
      // 传入的 middleware 参数必须是数组
      if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
    
      // middleware 数组的元素必须是函数
      for (const fn of middleware) {
        if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
      }
    
      /**
       * @param {Object} context
       * @return {Promise}
       * @api public
       */
    
      // 返回一个函数闭包, 保持对 middleware 的引用
      return function (context, next) {
        //context:
        // 这里的 context 参数是作为一个全局的设置, 所有中间件的第一个参数就是传入的 context, 这样可以在 context 中对某个值或者某些值做"洋葱处理"
        //next:
        // 这个传入的 next 函数  是在所有中间件执行后的"最后"一个函数, 这里的"最后"并不是真正的最后,
        // 而是像上面那个图中的圆心, 执行完圆心之后, 会返回去执行上一个中间件函数(middleware[length - 1])剩下的逻辑
    
    
        // index 是用来记录中间件函数运行到了哪一个函数
        let index = -1
    
        // 执行第一个中间件函数
        return dispatch(0)
        function dispatch (i) {
          // i 是洋葱模型的记录已经运行的函数中间件的下标, 如果一个中间件里面运行两次 next, 那么 i 是会比 index 小的.
          // 如果对这个地方不清楚可以查看下面的图
          if (i <= index) return Promise.reject(new Error('next() called multiple times'))
          index = i
          let fn = middleware[i]
          // 这里的 next 就是一开始 compose 传入的 next, 意味着当中间件函数数列执行完后, 执行这个 next 函数, 即圆心
          if (i === middleware.length) fn = next
    
          // 如果没有函数, 直接返回空值的 Promise
          if (!fn) return Promise.resolve()
          try {
            // 为什么这里要包一层 Promise? 
            // 因为 async 需要后面是 Promise, 然后 next 函数返回值就是 dispatch 函数的返回值, 所以运行 async next(); 需要 next 包一层 Promise
            // next 函数是固定的, 可以执行下一个函数
            return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
          } catch (err) {
            return Promise.reject(err)
          }
        }
      }
    }
    
    
    • 至于在一个中间件函数中两次调用 next 函数导致出错, 我这里提供一个简单的例子供大家参考:
    async function first(ctx, next) {
      console.log('1');
      await next();
      await next(); // 两次调用 next
      console.log(ctx);
    };
    
    async function second(ctx, next) {
      console.log('2');
      await next();
    };
    
    async function third(ctx, next) {
      console.log('3');
      await next();
      console.log('4');
    };
    
    const middleware = [first, second, third];
    
    const com = compose(middleware);
    
    com('ctx', function() {
      console.log('hey');
    });
    

    参考资料

    demo

    koa2

    展开全文
  • 2.koa中文文档 案例为了更简洁易懂,使用postman来代替前端界面请求接口。 下面案例获取请求的name值来生成token 代码: const Koa = require('koa') const Router = require('koa-router') const jw...
  • 演示代码戳此 jwt技术点实现的功能如下 1、server端会在前端访问部分接口...2、用户登录成功后,server端就会返回给前端一个加密了的有保质期的字符串,字符串中存储着用户登录的信息,这个字符串就是token,前端...
  • 版权声明 转载请告知并注明来源...Koa 框架教程 二、环境 Microsoft Visual Studio 2017集成开发环境 Node.js v8.9.4Javascript运行环境 三、开始动手,一步步来完善 1、创建基础的静态资源服务器、基础架构 ...
  • jwt实现注册与登陆系统

    千次阅读 2019-08-01 13:07:13
    前言 自己用react+koa实现了一个包含登陆和注册功能的网址,在这里记录一下实现过程 项目地址: 预览地址: 注册 注册其实没什么好说的,就是要注意不要明文保存密码,否则数据库泄露后,密码会被其他人用来撞库... ...
  • 环境:node.js + koa + koa-jwt + jsonwebtoken + mysql + sequelize 1.环境安装 npm install koa -S npm install koa-router -S npm i koa-bodyparser -S npm install koa-jwt jsonwebtoken -S npm install require...
  • Koa2基础知识

    2018-12-31 22:02:58
    第3章 Koa2基础知识 Node服务是全栈的核心,异步操作是为了提高并发数,koa2最大的特色就是灵活、轻巧,这都要归功于中间件机制。路由、数据库连接都是中间件的一种,通过这个章节的学习让大家掌握服务端开发基本...
  • koa2-热更新-使用nodemon

    千次阅读 2019-06-30 21:29:28
    1.因为没查找到为什么使用koa2 安装项目会报错的原因,所以没按照全栈开发美团网老师的要求来操作,自己在网上找的方法,记录一下继续上面的步骤后,如何热更新koa项目 2.具体步骤如下,我是用vscode直接在koa项目...
  • Koa2超详细入门教程

    2020-04-16 12:25:26
    Koa2 快速开始 环境准备 因为node.js v7.6.0开始完全支持async/await,不需要加flag,所以node.js环境都要7.6.0以上 node.js环境 版本v7.6以上 直接安装node.js 7.6:node.js官网地址https://nodejs.org nvm...
  • koa2

    2019-02-27 16:30:23
    ------------koa----------------- // automatically restarts npm install nodemon --save-dev npm install --save koa-router@7 const Router = require('koa-router') npm install --save koa-bodyparser@3...
  • Koa2基础 安装 1.初始化项目 npm init -y //-y是初始项目默认所有都是yes,若想另外设置可以直接npm init 2.安装koa2 npm i koa --save 基础用法 1.在文件目录下新建一个index.js,然后写下如下代码: ...
  • Koa2

    2020-06-28 15:15:17
    KOA2 **定义:**Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力...
  • Koa2 学习文档

    千次阅读 2017-08-03 08:44:56
    说明koa是express的轻量级版本。koa不绑定任何的中间件,但是依赖中间件来完成指定的... 注意:koa 1.x 和 koa 2.x有一些不同,下面内容都是围绕koa 2.x做介绍。 Koa安装$ mkdir mypp && cd myapp $ npm init $ npm i
  • 前言较早的Nodejs开发者为了实现程序的同步都会使用几个“工具”,回调,promise,co,或者是generator。记得写过一个递归删除目录下文件和文件夹的需求,用以上方法都是各种不爽(关键我就是想简单的写个递归啊)。...
  • 全栈02 Koa2+Vue2+MySQL 全栈的入门尝试

    万次阅读 多人点赞 2019-10-16 19:00:28
    0 前言 其实并没有想要成为全栈工程师的想法,因为我觉得自己作为一个半路出家、至今全职前端开发经验不到两年的程序猿来说,把前端稍微深入一点的东西搞明白就算不错。 但是心里其实一直有一些疑惑,比如,...
  • koa2框架使用心得

    2020-04-27 11:31:42
    文章目录一、express和koa2的区别二、安装koa21、使用脚手架2、路由3、ctx三、中间件四、session1、使用 koa-generic-session 和 koa-redis2、req.session 保存登录信息到redis3、登录校验做成express中间件五、日志...
  • Koa vs Express && Koa1 vs Koa2

    千次阅读 2018-06-11 16:09:00
    Koa vs Express 鉴于已选定 Koa 框架,故对 Express 未做深入学习,只是大致的了解了后作出的对比总结 相同点 本是同根生,相煎何太急 构建 web 应用的 node 框架 某些语法也无太大区别,如创建 http 服务 ...
1 2 3 4 5 ... 20
收藏数 21,848
精华内容 8,739
关键字:

koa2