koa@2学习笔记

作者: dravenxiaokai | 来源:发表于2017-10-25 18:28 被阅读0次

    前言:站在巨人的肩膀上,感谢前辈们的付出与贡献

    安装 koa 模块

    koa 需要 node v7.6.0 及以上版本,提供 ES6 和 async 函数支持

    $ npm install koa
    

    新建 hello.js

    const Koa = require('koa');
    const app = new Koa();
    
    // response
    app.use(ctx => {
      ctx.body = 'Hello Koa';
    });
    
    app.listen(3000);
    

    中间件

    普通函数

    app.use((ctx, next) => {
      const start = Date.now();
      return next().then(() => {
        const ms = Date.now() - start;
        console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
      });
    });
    

    async 函数(node v7.6.0+)

    app.use(async (ctx, next) => {
      const start = Date.now();
      await next();
      const ms = Date.now() - start;
      console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
    });
    

    中间件开发

    /* ./middleware/logger-async.js */
    
    function log( ctx ) {
        console.log( ctx.method, ctx.header.host + ctx.url )
    }
    
    module.exports = function () {
      return async function ( ctx, next ) {
        log(ctx);
        await next()
      }
    }
    
    /* index.js */
    const Koa = require('koa')
    const loggerAsync = require('./middleware/logger-async')
    var app = new Koa()
    
    app.use(loggerAsync())
    
    app.use((ctx) => {
        ctx.body = 'hello world'
    })
    app.listen(3000, 'localhost', () => {
        console.log('starting on port: ', 3000)
    })
    
    //控制台
    PS D:\workspace\koa2demo> node .\index.js
    starting on port:  3000
    GET localhost:3000/
    

    理解 async/await

    function getSyncTime() {
        return new Promise((resolve, reject) => {
            try {
                let startTime = new Date().getTime()
                setTimeout(() => {
                    let endTime = new Date().getTime()
                    let data = endTime - startTime
                    resolve(data)
                }, 500)
            } catch (err) {
                reject(err)
            }
        })
    }
    async function getSyncData() {
        let time = await getSyncTime()
        let data = `endTime - startTime = ${time}`
        return data
    } async function getData() {
        let data = await getSyncData()
        console.log(data)
    }
    getData()
    
    async/await

    koa2特性

    • 利用ES7的async/await的来处理传统回调嵌套问题和代替koa@1的generator
    • 中间件只支持 async/await 封装,如果要使用koa@1基于generator中间件,需要通过中间件koa-convert封装一下才能使用

    路由中间件 koa-router

    npm install koa-router --save
    
    /* index.js */
    const Koa = require('koa')
    const fs = require('fs')
    const app = new Koa()
    
    const Router = require('koa-router')
    
    //子路由1
    let home = new Router()
    home.get('/', async (ctx) => {
        let html = `
            <ul>
                <li><a href="/page/helloworld">/page/helloworld</a></li>
                <li><a href="/page/404">/page/404</a></li>
            </ul>
        `
        ctx.body = html
    })
    
    //子路由2
    let page = new Router()
    page
        .get('/404', async (ctx) => {
            ctx.body = '404 page'
        })
        .get('/helloworld', async (ctx) => {
            ctx.body = 'helloworld page'
        })
    
    //装载所有子路由
    let router = new Router()
    router.use('/', home.routes(), home.allowedMethods())
    router.use('/page', page.routes(), page.allowedMethods())
    
    //加载路由中间件
    app.use(router.routes()).use(router.allowedMethods())
    
    app.listen(3000, () => {
        console.log('[demo] koa-router is starting on port: 3000')
    })
    
    //console
    PS D:\workspace\koa2demo> node .\index.js
    [demo] koa-router is starting on port: 3000
    

    请求获取数据

    GET请求

    const Koa = require('koa')
    const app = new Koa()
    
    app.use(async (ctx)=>{
        let url = ctx.url
        //从上下文的request对象中获取
        let request = ctx.request
        let req_query = request.query
        let req_querystring = request.querystring
    
        //从上下文直接获取
        let ctx_query = ctx.query
        let ctx_querystring = ctx.querystring
    
        ctx.body = {
            url,
            req_query,
            req_querystring,
            ctx_query,
            ctx_querystring
        }
    })
    
    app.listen(3000, () => {
        console.log('[demo] get request is starting on port: 3000')
    })
    
    GET

    POST请求获取数据

    const Koa = require('koa')
    const app = new Koa()
    
    app.use(async (ctx) => {
        if (ctx.url === '/' && ctx.method === 'GET') {
            //get请求时返回表单
            let html = `
                <h2>koa@2 post request</h2>
                <form action="/" method="POST">
                    <p>userName</p>
                    <input name="username" type="text"><br>
                    <p>userPwd</p>
                    <input name="userPwd" type="password"><br>
                    <button type="submit">submit</button>
                </form>
            `
            ctx.body = html
        } else if (ctx.url === '/' && ctx.method === 'POST') {
            //post请求时,解析表单里数据,并显示
            let postData = await parsePostData(ctx)
            ctx.body = postData
        } else {
            //其他请求显示404
            ctx.body = '<h1>404 page</h1>'
        }
    })
    
    //解析上下文里node原生请求的post参数
    function parsePostData(ctx) {
        return new Promise((resolve, reject) => {
            try {
                let postData = '';
                ctx.req.addListener('data', (data) => {
                    postData += data
                })
                ctx.req.addListener('end', () => {
                    let parseData = parseQueryStr(postData)
                    resolve(parseData)
                })
            } catch (err) {
                reject(err)
            }
        })
    }
    
    //将post请求参数字符串解析成JSON
    function parseQueryStr(queryStr) {
        let queryData = {}
        let queryStrList = queryStr.split('&')
        console.log(queryStrList)
        for (let [index, queryStr] of queryStrList.entries()) {
            let itemList = queryStr.split('=')
            queryData[itemList[0]] = decodeURIComponent(itemList[1])
        }
        return queryData
    }
    
    app.listen(3000, () => {
        console.log('[demo] post request is starting on port: 3000')
    })
    
    POST表单请求 请求响应结果
    POST表单 提交结果

    koa-bodyparser 中间件

    const Koa = require('koa')
    const app = new Koa()
    const bodyParser = require('koa-bodyparser')
    
    //使用ctx.body解析中间件
    app.use(bodyParser())
    
    app.use(async (ctx) => {
        if (ctx.url === '/' && ctx.method === 'GET') {
            //get请求时返回表单
            let html = `
                <h2>koa@2 post request</h2>
                <form action="/" method="POST">
                    <p>userName</p>
                    <input name="username" type="text"><br>
                    <p>userPwd</p>
                    <input name="userPwd" type="password"><br>
                    <button type="submit">submit</button>
                </form>
            `
            ctx.body = html
        } else if (ctx.url === '/' && ctx.method === 'POST') {
            //post请求时,解析表单里数据,并显示
            let postData = ctx.request.body
            ctx.body = postData
        } else {
            //其他请求显示404
            ctx.body = '<h1>404 page</h1>'
        }
    })
    
    app.listen(3000, () => {
        console.log('[demo] koa-bodyparser is starting on port: 3000')
    })
    

    静态资源加载

    koa-static中间件

    const Koa = require('koa')
    const path = require('path')
    const static = require('koa-static')
    
    const app = new Koa()
    
    //静态资源相对路径
    const staticPath = './public'
    
    app.use(static(path.join(__dirname, staticPath)))
    
    app.use(async (ctx) => {
        ctx.body = 'hello koa@2'
    })
    
    app.listen(3000, () => {
        console.log('[demo] koa-static middleware is starting on port: 3000')
    })
    

    koa2使用cookie

    const Koa = require('koa')
    const app = new Koa()
    
    app.use(async (ctx) => {
        if (ctx.url === '/index') {
            ctx.cookies.set('cid', 'hello world', {
                domain: 'localhost',//cookie所在的域名
                path: '/index',//cookie所在的路径
                maxAge: 20 * 60 * 1000,//cookie有效时长
                expires: new Date('2018-10-24'),//cookie失效时间
                httpOnly: false,//是否只用于http请求中获取
                overwrite: false//是否允许重写
            })
            ctx.body = 'cookie is ok'
        } else {
            ctx.body = 'hello koa@2'
        }
    })
    
    app.use(async (ctx) => {
        ctx.body = 'hello koa@2'
    })
    
    app.listen(3000, () => {
        console.log('[demo] cookie is starting on port: 3000')
    })
    
    cookie

    koa2实现session

    存放mysql中

    //创建mysql数据库名为koademo
    CREATE DATABASE IF NOT EXISTS koademo DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
    
    const Koa = require('koa')
    const session = require('koa-session-minimal')
    const MysqlSession = require('koa-mysql-session')
    
    const app = new Koa()
    
    //配置存储session信息的mysql
    let store = new MysqlSession({
        user: 'root',
        password: 'root',
        database: 'koademo',
        host: '127.0.0.1'
    })
    
    //存放sessionId的cookie配置
    let cookie = {
        maxAge: '',
        expires: '',
        path: '',
        domain: '',
        httpOnly: '',
        overwrite: '',
        secure: '',
        sameSite: '',
        signed: ''
    }
    
    //使用session中间件
    app.use(session({
        key: 'SESSION_ID',
        store: store,
        cookie: cookie
    }))
    
    app.use(async (ctx) => {
        //设置session
        if (ctx.url === '/set') {
            ctx.session = {
                user_id: Math.random().toString(36).substr(2),
                count: 0
            }
            ctx.body = ctx.session
        } else if (ctx.url === '/') {
            //读取session信息
            ctx.session.count = ctx.session.count + 1
            ctx.body = ctx.session
        }
    })
    
    app.listen(3000, () => {
        console.log('[demo] session is starting on port: 3000')
    })
    

    加载模板引擎

    koa-views中间件

    const Koa = require('koa')
    const views = require('koa-views')
    const path = require('path')
    
    const app = new Koa()
    
    //加载模板引擎
    app.use(views(path.join(__dirname, './views'), {
        extension: 'ejs'
    }))
    
    app.use(async (ctx) => {
        let title = 'hello koa@2'
        await ctx.render('index', {
            title
        })
    })
    
    app.listen(3000, () => {
        console.log('[demo] koa-views ejs is starting on port: 3000')
    })
    

    文件上传

    busboy模块

    busboy模块是用来解析post请求,node原生req中的文件流

    const inspect = require('util').inspect
    const path = require('path')
    const fs = require('fs')
    const Busboy = require('busboy')
    
    //req为node原生请求
    const busboy = new Busboy({ headers: req.headers })
    
    //监听文件解析事件
    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
        console.log(`File [${fieldname}]: filename: ${filename}`)
    
        //文件保存特定路径
        file.pipe(fs.createWriteStream('./upload'))
    
        //开始解析文件流
        file.on('data', (data) => {
            console.log(`File [${fieldname}] got ${data.length} bytes`)
        })
    
        //解析文件结束
        file.on('end', () => {
            console.log(`File [${fieldname}] finished`)
        })
    })
    
    //监听请求中的字段
    busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated) => {
        console.log(`Field [${fieldname}]: value: ${inspect(val)}`)
    })
    
    //监听结束事件
    busboy.on('finish', () => {
        console.log('Done parsing form!')
        res.writeHead(303, { Connection: 'close', Location: '/' })
        res.end()
    })
    req.pipe(busboy)
    

    上传文件简单实现

    封装上传文件到写入服务方法

    const inspect = require('util').inspect
    const path = require('path')
    const os = require('os')
    const fs = require('fs')
    const Busboy = require('busboy')
    
    /**
    * 同步创建文件目录
    * @param  {string} dirname 目录绝对地址
    * @return {boolean}        创建目录结果
    */ function mkdirsSync(dirname) {
        if (fs.existsSync(dirname)) {
            return true
        } else {
            if (mkdirsSync(path.dirname(dirname))) {
                fs.mkdirSync(dirname)
                return true
            }
        }
    }
    
    /**
    * 获取上传文件的后缀名
    * @param  {string} fileName 获取上传文件的后缀名
    * @return {string}          文件后缀名
    */
    function getSuffixName(fileName) {
        let nameList = fileName.split('.')
        return nameList[nameList.length - 1]
    }
    
         /**
    * 上传文件
    * @param  {object} ctx     koa上下文
    * @param  {object} options 文件上传参数 fileType文件类型, path文件存放路径
    * @return {promise}         
    */ function uploadFile(ctx, options) {
        let req = ctx.req
        let res = ctx.res
        let busboy = new Busboy({ headers: req.headers }) // 获取类型 
        let fileType = options.fileType || 'common'
        let filePath = path.join(options.path, fileType)
        let mkdirResult = mkdirsSync(filePath)
        return new Promise((resolve, reject) => {
            console.log('文件上传中...')
            let result = { success: false, formData: {}, } // 解析请求文件事件 
            busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
                let fileName = Math.random().toString(16).substr(2) + '.' + getSuffixName(filename)
                let _uploadFilePath = path.join(filePath, fileName)
                let saveTo = path.join(_uploadFilePath) // 文件保存到制定路径 
                file.pipe(fs.createWriteStream(saveTo)) // 文件写入事件结束 
                file.on('end', function () {
                    result.success = true
                    result.message = '文件上传成功'
                    console.log('文件上传成功!')
                    resolve(result)
                })
            }) // 解析表单中其他字段信息 
            busboy.on('field', function (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
                console.log('表单字段数据 [' + fieldname + ']: value: ' + inspect(val));
                result.formData[fieldname] = inspect(val);
            }); // 解析结束事件 
            busboy.on('finish', function () {
                console.log('文件上结束')
                resolve(result)
            }) // 解析错误事件 
            busboy.on('error', function (err) {
                console.log('文件上出错')
                reject(result)
            })
            req.pipe(busboy)
        })
    }
    
    module.exports = { uploadFile }
    

    入口文件

    const Koa = require('koa')
    const path = require('path')
    const app = new Koa()
    // const bodyParser = require('koa-bodyparser')
    const { uploadFile } = require('./util/upload')
    // app.use(bodyParser()) 
    app.use(async (ctx) => {
        if (ctx.url === '/' && ctx.method === 'GET') {
            // 当GET请求时候返回表单页面
            let html = `
                <h1>koa2 upload demo</h1>
                <form method="POST" action="/upload.json" enctype="multipart/form-data">
                <p>file upload</p>
                <span>picName:</span><input name="picName" type="text" /><br/>
                <input name="file" type="file" /><br/><br/>
                <button type="submit">submit</button>
                </form>
            `
            ctx.body = html
        } else if (ctx.url === '/upload.json' && ctx.method === 'POST') {
            // 上传文件请求处理
            let result = {
                success: false
            }
            let serverFilePath = path.join(__dirname, 'upload-files')
            // 上传文件事件
            result = await uploadFile(ctx, {
                fileType: 'album', // common or album 
                path: serverFilePath
            })
            ctx.body = result
        } else {
            // 其他请求显示404 
            ctx.body = '<h1>404!!! o(╯□╰)o</h1>'
        }
    })
    
    app.listen(3000, () => {
        console.log('[demo] upload-simple is starting at port 3000')
    })
    

    异步上传图片

    入口文件
    const Koa = require('koa')
    const views = require('koa-views')
    const path = require('path')
    const convert = require('koa-convert')
    const static = require('koa-static')
    const { uploadFile } = require('./util/upload')
    const app = new Koa()
    
    /**
    * 使用第三方中间件 start 
    */
    app.use(views(path.join(__dirname, './views'), {
        extension: 'ejs'
    }))
    
    // 静态资源目录对于相对入口文件index.js的路径 
    const staticPath = './public'
    // 由于koa-static目前不支持koa2 
    // 所以只能用koa-convert封装一下 
    app.use(convert(static(path.join(__dirname, staticPath))))
    
    /**
    * 使用第三方中间件 end 
    */
    app.use(async (ctx) => {
        if (ctx.method === 'GET') {
            let title = 'upload pic async'
            await ctx.render('index', {
                title,
            })
        }
        else if (ctx.url === '/api/picture/upload.json' && ctx.method === 'POST') {
            // 上传文件请求处理 
            let result = { success: false }
            let serverFilePath = path.join(__dirname, 'public/image')
            // 上传文件事件 
            result = await uploadFile(ctx, {
                fileType: 'album',
                path: serverFilePath
            })
            ctx.body = result
        } else {
            // 其他请求显示404
            ctx.body = '<h1>404!!! o(╯□╰)o</h1>'
        }
    })
    
    app.listen(3000, () => {
        console.log('[demo] upload-async is starting at port 3000')
    })
    
    上传图片流写操作
    const inspect = require('util').inspect
    const path = require('path')
    const os = require('os')
    const fs = require('fs')
    const Busboy = require('busboy')
    
    /**
    * 同步创建文件目录
    * @param  {string} dirname 目录绝对地址
    * @return {boolean}        创建目录结果
    */
    function mkdirsSync(dirname) {
        if (fs.existsSync(dirname)) {
            return true
        } else {
            if (mkdirsSync(path.dirname(dirname))) {
                fs.mkdirSync(dirname)
                return true
            }
        }
    }
    
    /**
    * 获取上传文件的后缀名
    * @param  {string} fileName 获取上传文件的后缀名
    * @return {string}          文件后缀名
    */ function getSuffixName(fileName) {
        let nameList = fileName.split('.')
        return nameList[nameList.length - 1]
    }
    
    /**
    * 上传文件
    * @param  {object} ctx     koa上下文
    * @param  {object} options 文件上传参数 fileType文件类型, path文件存放路径
    * @return {promise}         
    */ function uploadFile(ctx, options) {
        let req = ctx.req
        let res = ctx.res
        let busboy = new Busboy({ headers: req.headers })
        // 获取类型 
        let fileType = options.fileType || 'common'
        let filePath = path.join(options.path, fileType)
        let mkdirResult = mkdirsSync(filePath)
        return new Promise((resolve, reject) => {
            console.log('文件上传中...')
            let result = { success: false, message: '', data: null }
            // 解析请求文件事件
            busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
                let fileName = Math.random().toString(16).substr(2) + '.' + getSuffixName(filename)
                let _uploadFilePath = path.join(filePath, fileName)
                let saveTo = path.join(_uploadFilePath)
                // 文件保存到制定路径 
                file.pipe(fs.createWriteStream(saveTo))
                // 文件写入事件结束 
                file.on('end', function () {
                    result.success = true
                    result.message = '文件上传成功'
                    result.data = {
                        pictureUrl: `//${ctx.host}/image/${fileType}/${fileName}`
                    }
                    console.log('文件上传成功!')
                    resolve(result)
                })
            })
            // 解析结束事件 
            busboy.on('finish', function () {
                console.log('文件上结束')
                resolve(result)
            })
            // 解析错误事件 
            busboy.on('error', function (err) {
                console.log('文件上出错')
                reject(result)
            })
            req.pipe(busboy)
        })
    }
    
    module.exports = { uploadFile }
    
    前端代码
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title><%= title%></title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
        </head>
        <body>
            <button class="btn" id="J_UploadPictureBtn">上传图片</button>
            <hr/>
            <p>上传进度<span id="J_UploadProgress">0</span>%</p>
            <p>上传结果图片</p>
            <div id="J_PicturePreview" class="preview-picture"> </div> 
            <script src="js/index.js"></script>
        </body>
    </html>
    

    上传操作代码

    (function () {
        let btn = document.getElementById('J_UploadPictureBtn')
        let progressElem = document.getElementById('J_UploadProgress')
        let previewElem = document.getElementById('J_PicturePreview')
        btn.addEventListener('click', function () {
            uploadAction({
                success: function (result) {
                    console.log(result)
                    if (result && result.success && result.data && result.data.pictureUrl) {
                        previewElem.innerHTML = '![](' + result.data.pictureUrl + ')'
                    }
                },
                progress: function (data) {
                    if (data && data * 1 > 0) {
                        progressElem.innerText = data
                    }
                }
            })
        })
    
        /**
        * 类型判断
        * @type {Object}
        */
        let UtilType = {
            isPrototype: function (data) {
                return Object.prototype.toString.call(data).toLowerCase();
            }, isJSON: function (data) {
                return this.isPrototype(data) === '[object object]';
            }, isFunction: function (data) {
                return this.isPrototype(data) === '[object function]';
            }
        }
    
        /**
        * form表单上传请求事件
        * @param  {object} options 请求参数
        */
        function requestEvent(options) {
            try {
                let formData = options.formData
                let xhr = new XMLHttpRequest()
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        options.success(JSON.parse(xhr.responseText))
                    }
                }
                xhr.upload.onprogress = function (evt) {
                    let loaded = evt.loaded
                    let tot = evt.total
                    let per = Math.floor(100 * loaded / tot)
                    options.progress(per)
                }
                xhr.open('post', '/api/picture/upload.json')
                xhr.send(formData)
            } catch (err) { options.fail(err) }
        }
    /**
    * 上传事件
    * @param  {object} options 上传参数      
    */ function uploadEvent(options) {
            let file
            let formData = new FormData()
            let input = document.createElement('input')
            input.setAttribute('type', 'file')
            input.setAttribute('name', 'files')
            input.click()
            input.onchange = function () {
                file = input.files[0]
                formData.append('files', file)
                requestEvent({ formData, success: options.success, fail: options.fail, progress: options.progress })
            }
        }
    
        /**
        * 上传操作
        * @param  {object} options 上传参数     
        */
        function uploadAction(options) {
            if (!UtilType.isJSON(options)) {
                console.log('upload options is null')
                return
            }
            let _options = {}
            _options.success = UtilType.isFunction(options.success) ? options.success : function () { }
            _options.fail = UtilType.isFunction(options.fail) ? options.fail : function () { }
            _options.progress = UtilType.isFunction(options.progress) ? options.progress : function () { }
            uploadEvent(_options)
        }
    })()
    

    创建mysql数据库连接池

    const mysql = require('mysql')
    
    //创建数据连接池
    const pool = mysql.createPool({
        host: '127.0.0.1',
        user: 'root',
        password: 'root',
        database: 'koademo'
    })
    
    //在数据池中进行会话操作
    pool.getConnection((err, conn) => {
        conn.query('SELECT * FROM test', (err, rs, fields) => {
            //结束会话
            conn.release()
    
            if (err) throw err
        })
    })
    

    async/await封装使用mysql

    /* ./async-db.js */
    const msyql = require('mysql')
    const pool = msyql.createPool({
        host: '127.0.0.1',
        user: 'root',
        password: 'root',
        database: 'koademo'
    })
    
    let query = (sql, values) => {
        return new Promise((resolve, reject) => {
            pool.getConnection((err, conn) => {
                if (err) {
                    reject(err)
                } else {
                    conn.query(sql, values, (err, rows) => {
                        if (err) {
                            reject(err)
                        } else {
                            resolve(rows)
                        }
                        conn.release()
                    })
                }
            })
        })
    }
    
    module.exports = {
        query
    }
    
    /* index.js */
    const { query } = require('./async-db')
    
    async function selectAllData() {
        let sql = 'SELECT * FROM test'
        let dataList = await query(sql)
        return dataList
    }
    
    async function getData() {
        let dataList = await selectAllData()
        console.log(dataList)
    }
    
    getData()
    

    jsonp

    const Koa = require('koa')
    const app = new Koa()
    
    app.use(async (ctx) => {
        //如果JSONP的请求为GET
        if (ctx.method === 'GET' && ctx.url.split('?')[0] === '/getData.jsonp') {
            //获取JSONP的callback
            let callbackName = ctx.query.callback || 'callback'
            let returnData = {
                success: true,
                data: {
                    text: 'this is a jsonp api',
                    time: new Date().getTime()
                }
            }
            //JSONP的script字符串
            let jsonpStr = `;${callbackName}(${JSON.stringify(returnData)})`
            //用text/javascript,让请求支持跨域请求
            ctx.type = 'text/javascript'
            //输出jsonp字符串
            ctx.body = jsonpStr
        } else {
            ctx.body = 'hello jsonp'
        }
    })
    app.listen(3000, () => {
        console.log('[demo] jsonp is tarting on port 3000')
    })
    

    koa-jsonp中间件

    const Koa = require('koa')
    const jsonp = require('koa-jsonp')
    const app = new Koa()
    
    //使用中间件
    app.use(jsonp())
    
    app.use(async (ctx) => {
        let returnData = {
            success: true,
            data: {
                text: 'this is a jsonp api',
                time: new Date().getTime()
            }
        }
        //直接输出json
        ctx.body = returnData
    })
    app.listen(3000, () => {
        console.log('[demo] koa-jsonp is tarting on port 3000')
    })
    

    各章节代码存放在对应的分支中:所有源码

    相关文章

      网友评论

        本文标题:koa@2学习笔记

        本文链接:https://www.haomeiwen.com/subject/nkyxpxtx.html