【從前端到全棧】- koa快速入門指南

薄荷前端發表於2019-03-02

前言

隨著技術的不斷髮展,前端工程師也被賦予了越來越多的職責。不再是從前只需要切個圖,加個css樣式就能完成任務的切圖仔了。接下來這篇文章,完成一個簡單的登入註冊,能讓你快速上手,成為一個‘小全棧工程師’,here we go !

15371488705139

koa快速開始

安裝

  • 因為node.js v7.6.x已經完全支援async/await語法,所以請保證node的版本在7.6以上
  • 推薦一個node的多版本管理工具:nvm。如何安裝這裡不再贅述,網上的教程有很多

// 初始化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
複製程式碼

就可以看到執行結果啦:

15371507388772

幾個核心概念

中介軟體好基友ctx和next

在上面的程式碼中,我們可以看到app.use後面使用了2個引數,ctxnext,下面我們介紹一個這哥倆到底幹嘛的

ctx

ctx作為上下文使用,Koa將 node 的 request, response 物件封裝進一個單獨物件。即ctx.requestctx.response。Koa 內部又對一些常用的屬性或者方法做了代理操作,使得我們可以直接通過 ctx 獲取。比如,ctx.request.url 可以寫成 ctx.url

next

next 引數的作用是將處理的控制權轉交給下一個中介軟體

15371520197565

經典的洋蔥圖概念能很好的解釋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`)
})
複製程式碼

看一下執行結果:

15371528106452

如果將**‘222’**函式的next()去掉的話,會發生什麼呢?

15371529369320

可以看到,後面的**‘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`)
})

複製程式碼
15371540305250
15371540448439
15371540585094

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`)
})
複製程式碼

看一下執行結果:

15371560100616
15371560354693
15371560521654

獲取請求資料

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 ,可以看到執行結果

15371636443212

可以看到區別,.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 看到結果

15371643392037

接下來我們看看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 = `啊哦~你填寫的資訊有誤`
  }

})
複製程式碼

看一下執行結果

2018-09-17 14 26 24

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 = `啊哦~你填寫的資訊有誤`
  }

})
複製程式碼

看一下執行結果:

15371681204265
15371681313023

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有一個初步的印象和概念。下篇文章我們會有中介軟體的拆分,單元測試,記錄日誌,管理規範等。讓我們共同成長!

廣而告之

本文釋出於薄荷前端週刊,歡迎Watch & Star ★,轉載請註明出處。

歡迎討論,點個贊再走吧 。◕‿◕。 ~

相關文章