10分鐘讓你成為全棧工程師-koa快速入門
前言
隨著技術的不斷髮展,前端工程師也被賦予了越來越多的職責。不再是從前只需要切個圖,加個css樣式就能完成任務的切圖仔了。接下來這篇文章,完成一個簡單的登入註冊,能讓你快速上手,成為一個‘小全棧工程師’,here we go !
koa快速開始
安裝
- 因為node.js v7.6.x已經完全支援async/await語法,所以請保證node的版本在7.6以上
// 初始化package.json
npm init
// 安裝koa2
npm install koa
一個hello world
新建一個index.js,敲上以下程式碼
//index.js const Koa = require('koa') const app = new Koa() app.use( async (ctx, next) => { ctx.response.body = '你好,我是內地吳彥祖' }) app.listen(3333, ()=>{ console.log('server is running at http://localhost:3333') })
在我們的命令列敲上
node index.js
就可以看到執行結果啦:
幾個核心概念
中介軟體好基友ctx和next
在上面的程式碼中,我們可以看到app.use後面使用了2個引數,ctx和next,下面我們介紹一個這哥倆到底幹嘛的
ctx
ctx作為上下文使用,Koa將 node 的 request, response 物件封裝進一個單獨物件。即ctx.request 、 ctx.response。Koa 內部又對一些常用的屬性或者方法做了代理操作,域名劫持,使得我們可以直接通過 ctx 獲取。比如,ctx.request.url 可以寫成 ctx.url。
next
next 引數的作用是將處理的控制權轉交給下一個中介軟體
經典的洋蔥圖概念能很好的解釋next的執行,請求從最外層進去,又從最裡層出來。我們看一個例子
const Koa = require('koa') const app = new Koa() app.use(async (ctx, next)=>{ let startTime = new Date().getTime() await next() let endTime = new Date().getTime() console.log(`此次的響應時間為:${endTime - startTime}ms`) }) app.use(async (ctx, next) => { console.log('111, 然後doSomething') await next() console.log('111 end') }) app.use(async (ctx, next) => { console.log('222, 然後doSomething') await next() console.log('222 end') }) app.use(async (ctx, next) => { console.log('333, 然後doSomething') await next() console.log('333 end') }) app.listen(3333, ()=>{ console.log('server is running at http://localhost:3333') })
看一下執行結果:
如果將‘222’函式的next()去掉的話,會發生什麼呢?
可以看到,後面的‘333’中介軟體直接不執行了。所以中介軟體的順序對next的執行有很大的影響
路由 koa-router
我們常用koa-router來處理URL
安裝
npm i koa-router --save
看一個例子:
const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')
const router = new Router()
router.get('/', async (ctx, next) => {
ctx.body = '你好,我這裡是index頁'
})
router.get('/user', async (ctx, next) => {
ctx.body = '你好,我這裡是user頁'
})
router.get('/error', async (ctx, next) => {
ctx.body = '你好,我這裡是error頁'
})
app.use(router.routes())
app.listen(3333, ()=>{
console.log('server is running at http://localhost:3333')
})
koa-router也支援巢狀寫法,通過一個總路由裝載所有子路由,也非常的方便。看一個例子:
const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')
// 子路由1
let oneRouter = new Router()
oneRouter.get('/', async (ctx, next) => {
ctx.body = '你好,我這裡是oneRouter頁'
})
// 子路由2
let twoRouter = new Router()
twoRouter.get('/', async (ctx, next) => {
ctx.body = '你好, 我這裡是twoRouter頁'
}).get('/home', async (ctx , next) => {
ctx.body = '你好, 我這裡是home頁'
})
// 裝載所有子路由
let indexRouter = new Router()
indexRouter.use('/one',oneRouter.routes(), oneRouter.allowedMethods())
indexRouter.use('/two',twoRouter.routes(), twoRouter.allowedMethods())
app
.use(indexRouter.routes())
.use(indexRouter.allowedMethods())
app.listen(3333, ()=>{
console.log('server is running at http://localhost:3333')
})
看一下執行結果:
獲取請求資料
koa-router提供了常見的 .get .put .post .del 介面來處理各種需求。實際開發中我們用的比較多的是get和post,我們來看看get例子:
const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')
const router = new Router()
router.get('/data', async (ctx , next)=> {
let url = ctx.url
// 從ctx的request中拿到我們想要的資料
let data = ctx.request.query
let dataQueryString = ctx.request.querystring
ctx.body = {
url,
data,
dataQueryString
}
})
app.use(router.routes())
app.listen(3333, ()=>{
console.log('server is running at http://localhost:3333')
})
在瀏覽器裡輸入http://localhost:3333/data?user=wuyanzu&id=123456 ,可以看到執行結果
可以看到區別,.query
返回的結果是物件,而.querystring
返回的是字串,這個很好理解。(chrome外掛顯示成json格式)
如果遵從 RESTful 規範,比如請求要以 '/user/:id'的方式發出的話,我們可以用下面的例子來獲取到想要的資料
新增程式碼
router.get('/data/:id', async (ctx, next) => {
// 也從ctx中拿到我們想要的資料,不過使用的是params物件
let data = ctx.params
ctx.body = data
})
瀏覽器執行 http://localhost:3333/data/4396 看到結果
接下來我們看看post的例子
我們常用的請求post,它的資料是放在body當中的。這個時候就推薦一個非常常用且好用的中介軟體-koa-bodyparser
首先安裝
npm i koa-bodyparser --save
然後我們在剛才的程式碼裡新增
router.get('/post', async (ctx, next) => {
// 模擬一段提交頁面
let html = `
<form action="/post/result" method="post">
<p>你長的最像哪位明星</p>
<input name="name" type="text" placeholder="請輸入名字:"/>
<br/>
<p>輸入一段你知道的車牌號</p>
<input name="num" type="text" placeholder="請輸入車牌號:"/>
<br/>
<button>確定不改了哦</button>
</form> `
ctx.body = html
})
router.post('/post/result', async (ctx, next) => {
// 我們可以從ctx的request.body拿到提交上來的資料
let {name, num} = ctx.request.body
if (name && num) {
ctx.body = `hello,你最像的明星是:${name},ch你知道的車牌號是:${num}`
} else {
ctx.body = '啊哦~你填寫的資訊有誤'
}
})
看一下執行結果
cache
koa操作cookie是非常方便的,也是從上下文ctx中獲取。
- ctx.cookies.get(name, [options]) 讀取上下文請求中的cookie
- ctx.cookies.set(name, value, [options]) 在上下文中寫入cookie
在我們剛才的post請求的程式碼中加入:
router.post('/post/result', async (ctx, next) => {
// 我們可以從ctx的request.body拿到提交上來的資料
let {name, num} = ctx.request.body
if (name && num) {
ctx.body = `hello,你最像的明星是:${name},ch你知道的車牌號是:${num}`
ctx.cookies.set(
'xunleiCode',num,
{
domain: 'localhost', // 寫cookie所在的域名
path: '/post/result', // 寫cookie所在的路徑
maxAge: 10 * 60 * 1000, // cookie有效時長
expires: new Date('2018-09-17'), // cookie失效時間
httpOnly: false, // 是否只用於http請求中獲取
overwrite: false // 是否允許重寫
}
)
} else {
ctx.body = '啊哦~你填寫的資訊有誤'
}
})
看一下執行結果:
koa操作session的話,需要用到koa-session,?:
const session = require('koa-session')
app.keys = ['some secret hurr'];
const CONFIG = {
key: 'koa:sess', //cookie key (default is koa:sess)
maxAge: 86400000, // cookie的過期時間 maxAge in ms (default is 1 days)
overwrite: true, //是否可以overwrite (預設default true)
httpOnly: true, //cookie是否只有伺服器端可以訪問 httpOnly or not (default true)
signed: true, //簽名預設true
rolling: false, //在每次請求時強行設定cookie,這將重置cookie過期時間(預設:false)
renew: false, //(boolean) renew session when session is nearly expired,
};
app.use(session(CONFIG, app));
小結
在涉及到自己沒有接觸過的領域時,我一直推崇先看看要怎麼玩,等自己會玩了以後,再看看“究竟”怎麼玩。我們通過上面的程式碼和描述,已經對koa及node有一個初步的印象和概念。下篇文章我們會有中介軟體的拆分,單元測試,記錄日誌,管理規範等。讓我們共同成長!