上個月在作新系統開發的時候,團隊啓用了阿里系的Egg.js,基於koa的Node框架,有興趣的童鞋能夠到Egg.js官網看看。在此基礎上本身學習了koa2,作了一些簡單筆記。html
Node版本>=7.6.0,才支持async
和await
node
# 初始化package.json
npm init
# 安裝koa2
npm install koa
複製代碼
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
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')
複製代碼
若是依靠ctx.request.url去手動處理路由,將會寫不少處理代碼,這時候就須要對應的路由的中間件對路由進行控制,這裏介紹一個比較好用的路由中間件koa-routerbash
# 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')
})
複製代碼
在koa中,獲取GET請求數據源頭是koa中request對象中的query方法或querystring方法,query返回是格式化好的參數對象,querystring返回的是請求字符串,因爲ctx對request的API有直接引用的方式,因此獲取GET請求數據有兩個途徑。app
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請求的處理,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
// 解析上下文裏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
}
複製代碼
對於POST請求的處理,koa-bodyparser中間件能夠把koa2上下文的formData數據解析到ctx.request.body中異步
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')
})
複製代碼
未完待續...