koa2學習筆記(一)

背景

上個月在作新系統開發的時候,團隊啓用了阿里系的Egg.js,基於koa的Node框架,有興趣的童鞋能夠到Egg.js官網看看。在此基礎上本身學習了koa2,作了一些簡單筆記。html

HelloWorld

環境準備

Node版本>=7.6.0,才支持asyncawaitnode

安裝koa2

# 初始化package.json
npm init

# 安裝koa2 
npm install koa
複製代碼

Hello World代碼

const Koa = require('koa')
const app = new Koa()

app.use( async ( ctx ) => {
  ctx.body = 'hello koa2'
})

app.listen(3000)
console.log('[demo] start-quick is starting at port 3000')
複製代碼

啓動

node index.js npm

async/await使用

特色

  • 能夠讓異步邏輯用同步寫法實現
  • 最底層的await返回須要是Promise對象
  • 能夠經過多層 async function 的同步寫法代替傳統的callback嵌套

實例代碼

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()
複製代碼

執行以後能夠打印出時間差。json

路由

簡單例子

const Koa = require('koa')
const app = new Koa()

app.use( async ( ctx ) => {
  let url = ctx.request.url
  ctx.body = url
})
app.listen(3000)
複製代碼

訪問 http://localhost:3000/hello/world 頁面會輸出 /hello/world,也就是說上下文的請求request對象中url之就是當前訪問的路徑名稱,能夠根據ctx.request.url 經過必定的判斷或者正則匹配就能夠定製出所須要的路由。promise

原生路由實現

const Koa = require('koa')
const fs = require('fs')
const app = new Koa()

/** * 用Promise封裝異步讀取文件方法 * @param {string} page html文件名稱 * @return {promise} */
function render( page ) {
  return new Promise(( resolve, reject ) => {
    let viewUrl = `./view/${page}`
    fs.readFile(viewUrl, "binary", ( err, data ) => {
      if ( err ) {
        reject( err )
      } else {
        resolve( data )
      }
    })
  })
}

/** * 根據URL獲取HTML內容 * @param {string} url koa2上下文的url,ctx.url * @return {string} 獲取HTML文件內容 */
async function route( url ) {
  let view = '404.html'
  switch ( url ) {
    case '/':
      view = 'index.html'
      break
    case '/index':
      view = 'index.html'
      break
    case '/todo':
      view = 'todo.html'
      break
    case '/404':
      view = '404.html'
      break
    default:
      break
  }
  let html = await render( view )
  return html
}

app.use( async ( ctx ) => {
  let url = ctx.request.url
  let html = await route( url )
  ctx.body = html
})

app.listen(3000)
console.log('[demo] route-simple is starting at port 3000')
複製代碼

koa-router中間件

若是依靠ctx.request.url去手動處理路由,將會寫不少處理代碼,這時候就須要對應的路由的中間件對路由進行控制,這裏介紹一個比較好用的路由中間件koa-routerbash

安裝koa-router中間件

# koa2 對應的版本是 7.x
npm install --save koa-router@7
複製代碼

實例代碼

const Koa = require('koa')
const fs = require('fs')
const app = new Koa()

const Router = require('koa-router')

let home = new Router()

// 子路由1
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] route-use-middleware is starting at port 3000')
})
複製代碼

數據請求

GET請求數據獲取

在koa中,獲取GET請求數據源頭是koa中request對象中的query方法或querystring方法,query返回是格式化好的參數對象,querystring返回的是請求字符串,因爲ctx對request的API有直接引用的方式,因此獲取GET請求數據有兩個途徑。app

  • 從上下文中直接獲取,請求對象ctx.query,返回如 { a:1, b:2 },請求字符串 ctx.querystring,返回如 a=1&b=2
  • 從上下文的request對象中獲取,請求對象ctx.request.query,返回如 { a:1, b:2 },請求字符串 ctx.request.querystring,返回如 a=1&b=2

實例代碼

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] request get is starting at port 3000')
})
複製代碼

POST請求數據獲取

原理

對於POST請求的處理,koa2沒有封裝獲取參數的方法,須要經過解析上下文context中的原生node.js請求對象req,將POST表單數據解析成query string(例如:a=1&b=2&c=3),再將query string 解析成JSON格式(例如:{"a":"1", "b":"2", "c":"3"}框架

注意:ctx.request是context通過封裝的請求對象,ctx.req是context提供的node.js原生HTTP請求對象,同理ctx.response是context通過封裝的響應對象,ctx.res是context提供的node.js原生HTTP請求對象。koa

解析出POST請求上下文中的表單數據

// 解析上下文裏node原生請求的POST參數
function parsePostData( ctx ) {
  return new Promise((resolve, reject) => {
    try {
      let postdata = "";
      ctx.req.addListener('data', (data) => {
        postdata += data
      })
      ctx.req.addListener("end",function(){
        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
}
複製代碼

koa-bodyparser中間件

對於POST請求的處理,koa-bodyparser中間件能夠把koa2上下文的formData數據解析到ctx.request.body中異步

安裝koa2版本的koa-bodyparser@3中間件

npm install --save koa-bodyparser@3
複製代碼

實例代碼

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 = ` <h1>koa2 request post demo</h1> <form method="POST" action="/"> <p>userName</p> <input name="userName" /><br/> <p>nickName</p> <input name="nickName" /><br/> <p>email</p> <input name="email" /><br/> <button type="submit">submit</button> </form> `
    ctx.body = html
  } else if ( ctx.url === '/' && ctx.method === 'POST' ) {
    // 當POST請求的時候,中間件koa-bodyparser解析POST表單裏的數據,並顯示出來
    let postData = ctx.request.body
    ctx.body = postData
  } else {
    // 其餘請求顯示404
    ctx.body = '<h1>404!!! o(╯□╰)o</h1>'
  }
})

app.listen(3000, () => {
  console.log('[demo] request post is starting at port 3000')
})
複製代碼

結語

未完待續...

相關文章
相關標籤/搜索