Koa2 初體驗(yàn)

一盏浙、起步

首先創(chuàng)建一個(gè)文件夾,然后初始化 package.json :

npm init -y

安裝koa2:

cnpm i koa --save

在文件目錄下新建一個(gè)index.js纺蛆,然后寫下如下代碼:

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

app.use( async(ctx) => {
    ctx.body = "hello world"
})
app.listen(1996)
console.log("demo in run")

然后運(yùn)行這個(gè)文件:

nodemon index.js

然后我們就能在后臺(tái)看見這個(gè):

demo is run

然后打開瀏覽器逞度,輸入 http://127.0.0.1:1996就可以看見這個(gè)了:

輸入圖片說明

這樣我們就搭建好了最簡(jiǎn)單的web服務(wù)器。但除了這些帘睦,有一點(diǎn)需要知道的是,在koa2中坦康,async函數(shù)已經(jīng)大規(guī)模使用了竣付,它很好的處理了異步的邏輯,所以學(xué)習(xí)koa2之前滞欠,勁量將async和await解決掉:

const wait1 = () => {
return new Promise(resolve => {
      setTimeout(() => { 
          resolve()
          console.log("1s later")
        }, 1000)
})
}

const  wait2 = () => {
    return new Promise((resolve) => {
        resolve(setTimeout(()=>{console.log("2s later")},2000))
    })
}
async function test() {
    const a = await wait1()
    const b = await wait2()
    console.log("end")
}
console.log("start")
test()

上面的代碼執(zhí)行起來就是這樣的:

start
1s later
end
2s later

它很好的解決了異步的一些麻煩古胆,且寫出來的代碼的可讀性也非常好。

二仑撞、請(qǐng)求數(shù)據(jù)獲取

2.1 Get請(qǐng)求的接收

在Koa2中GET請(qǐng)求可以通過 request 接受收赤兴,但接受的方式有兩種:

  • query:返回的是格式化后的參數(shù)對(duì)象
  • querystring:返回的請(qǐng)求字符串

我們可以由兩種方式來獲取GET請(qǐng)求妖滔,一種是通過 ctx.request 來獲取GET請(qǐng)求隧哮,一種則是直接在ctx中得到GET請(qǐng)求:

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

app.use(async(ctx) => {
    const url = ctx.url
    // 使用 ctx.request
    const request = ctx.request
    const req_query = request.query
    const req_querystring = request.querystring
    // 直接使用ctx來獲取
    const req_ctx = ctx.query
    const req_ctx1 = ctx.querystring
    ctx.body = {
        url,
        req_query,
        req_querystring,
        req_ctx,
        req_ctx1,
    }

})
app.listen(3000,() => {
    console.log("demo1 is run")
})

然后我們?cè)跒g覽器中輸入 http://127.0.0.1:3000?user=srtian&age=18 來訪問頁(yè)面就可以看到這個(gè)(這是經(jīng)過美化的表現(xiàn)):

輸入圖片說明

2.2 POST請(qǐng)求的接收

在 Koa2 中,沒有給對(duì)于 POST 請(qǐng)求的處理封裝方便的獲取參數(shù)的方法座舍,需要通過通過解析上下文 context 中的元素 node.js 請(qǐng)求對(duì)象 req 來獲取沮翔。因此獲取POST請(qǐng)求的步驟可以理解為以下三步:

  1. 解析上下文 ctx 中的原生 node.js 對(duì)象 req。
  2. 將POST表單數(shù)據(jù)解析成 query string 字符串曲秉。
  3. 將字符串轉(zhuǎn)換成 JSON 格式采蚀。
const Koa = require('koa')
const app = new Koa()

app.use(async(ctx) => {
    if (ctx.url === '/' && ctx.method === 'GET') {
        let html = `
        <h2>This is demo2</h2>
        <form method="POST" action="/">
            <p>username:</p>
            <input name="username">
            <p>age:</p>
            <input name="age">
            <p>website</p>
            <input name="website">
            <button type="submit">submit</button>                   
        </form>
        `
        ctx.body = html
    } else if (ctx.url === '/' && ctx.method === 'POST') {
        let postData = await parsePostDate(ctx)
        ctx.body = postData
    } else {
        ctx.body = '<h2>404</h2>'
    }
})

const parsePostDate = (ctx) => {
    return new Promise((resolve, reject) => {
        try{
            let postData = ""
            ctx.req.on('data', (data) => {
                postData += data
            })
            ctx.req.addListener("end", function() {
                let parseData = parseQueryStr(postData)
                resolve(parseData)
            })
        } catch(error) {
            reject(error)
         }
    })
}

const parseQueryStr = (queryStr) => {
    const queryData = {}
    const queryStrList = queryStr.split('&')
    console.log(queryStrList)
    for (let [index,queryStr] of queryStrList.entries()) {
        let itemList = queryStr.split('=')
        console.log(itemList)
        queryData[itemList[0]] = decodeURIComponent(itemList[1])
    }
    return queryData
}

app.listen(3000, () => {
    console.log('dom2 is run')
})

然后打開瀏覽器,輸入http://127.0.0.1:3000/:


輸入圖片說明

完善信息后承二,點(diǎn)擊submit:

輸入圖片說明

koa-bodyparser中間件

顯然上面的 POST 請(qǐng)求的接受非常麻煩榆鼠,至少對(duì)我而言,徒手寫個(gè)這樣的輪子在不查資料的情況下是做不到的亥鸠,而這樣的輪子當(dāng)然也有人來做妆够,koa-bodyparser就是一個(gè)造好的輪子识啦。我們?cè)趉oa中把這種輪子就叫做中間件。對(duì)于POST請(qǐng)求的處理神妹,koa-bodyparser中間件可以把koa2上下文的formData數(shù)據(jù)解析到ctx.request.body中颓哮。

首先我們要安裝中間件:

cnpm i koa-bodyparser@3 --save

然后我們就能非常輕松愉快的使用這個(gè)中間件來改造我們上面的代碼了:

const Koa  = require('koa')
const app = new Koa()
const bodyParser = require('koa-bodyparser')
 
app.use(bodyParser())
 
app.use(async(ctx) => {
    if (ctx.url === '/' && ctx.method === 'GET') {
        let html = `
        <h2>This is demo2</h2>
        <form method="POST" action="/">
            <p>username:</p>
            <input name="username">
            <p>age:</p>
            <input name="age">
            <p>website</p>
            <input name="website">
            <button type="submit">submit</button>                 
        </form>
        `
        ctx.body = html
    } else if (ctx.url === '/' && ctx.method === 'POST') {
        let postData = ctx.request.body
        ctx.body = postData
    } else {
        ctx.body = '<h2>404</h2>'
    }
})

 
 
app.listen(3000, () => {
    console.log('demo2 is run')
})

Koa2 路由

Koa2 原生路由的實(shí)現(xiàn)

路由在web中的作用不言而喻,而要先實(shí)現(xiàn)原生路由鸵荠,需要的到地址欄輸入的路徑冕茅,然后再根據(jù)路徑不同進(jìn)行跳轉(zhuǎn)。而在Koa2中蛹找,我們可以用 ctx.requerst.url 來實(shí)現(xiàn)獲取訪問路徑:

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

app.use(async(ctx) => {
    const url = ctx.request.url
    ctx.body = url 
})

app.listen(3000, () => {
    console.log('demo3 is run')
})

加入我們的文件結(jié)構(gòu)是這樣的:

├── demo3.js
├── package.json
└── view
    ├── register.html
    ├── index.html
    └── login.html

我們就可以這樣來實(shí)現(xiàn)原生路由:

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

function render(page) {
    return new Promise((resolve, reject) => {
        let viewUrl = `./view/${page}`
        fs.readFile(viewUrl, "binary", (err, data) => {
            console.log(1)
            if (err) {
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}
async function route(url) {
    let view = '404.html'
    switch(url) {
        case '/':
            view = 'index.html'
            break
        case '/login':
            view = 'login.html'
            break
        case '/register':
            view = 'register.html'
            break
        case '/index':
            view = 'index.html'
            break
        default:
            break
    }
    let html = await render(view)
    return html
}

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

app.listen(3000, () => {
    console.log('demo3 is run')
})

通過上面的代碼姨伤,我們成功實(shí)現(xiàn)了一個(gè)路由切換的功能,但這樣寫無(wú)疑是不夠優(yōu)雅的庸疾,且也只是在原理上的實(shí)現(xiàn)姜挺,不足以應(yīng)付我們?nèi)粘i_發(fā)中所遇到的種種問題。因此我們和上次一樣彼硫,還是需要引入中間件來達(dá)成我們的目標(biāo)炊豪。

koa-router

首先我們需要下載 koa-router 中間件:

cnpm i koa-router --save

然后我們就能通過koa-router來優(yōu)雅的進(jìn)行路由調(diào)換了:

const Koa = require('koa')
const fs = require('fs')
const app = new Koa()
const Router = require('koa-router')
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('demo4 is run')
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拧篮,隨后出現(xiàn)的幾起案子词渤,更是在濱河造成了極大的恐慌,老刑警劉巖串绩,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缺虐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡礁凡,警方通過查閱死者的電腦和手機(jī)高氮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來顷牌,“玉大人剪芍,你說我怎么就攤上這事】呃叮” “怎么了罪裹?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)运挫。 經(jīng)常有香客問我状共,道長(zhǎng),這世上最難降的妖魔是什么谁帕? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任峡继,我火速辦了婚禮,結(jié)果婚禮上匈挖,老公的妹妹穿的比我還像新娘碾牌。我一直安慰自己颠猴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布小染。 她就那樣靜靜地躺著翘瓮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裤翩。 梳的紋絲不亂的頭發(fā)上资盅,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音踊赠,去河邊找鬼呵扛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛筐带,可吹牛的內(nèi)容都是我干的今穿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伦籍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蓝晒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帖鸦,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芝薇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后作儿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洛二,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年攻锰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晾嘶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娶吞,死狀恐怖垒迂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寝志,我是刑警寧澤娇斑,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布策添,位于F島的核電站材部,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏唯竹。R本人自食惡果不足惜乐导,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浸颓。 院中可真熱鬧物臂,春花似錦旺拉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至仪媒,卻和暖如春沉桌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背算吩。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工留凭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人偎巢。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓蔼夜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親压昼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子求冷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容