koa2学习笔记

2019-02-10  本文已影响0人  地平线0530

快速开始

安装

node.js 版本:v7.6 以上

npm i koa -S

运行

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

app.use(async ctx => {
  ctx.body = 'Hello Koa'
})

app.listen(3000, () => {
  console.log(`服务运行于:http://localhost:3000`)
})

async / await 使用

简单理解:

async 是让方法变成异步,返回值是一个 Promise 对象

await 是等待异步方法执行完成

async(MDN)

await(MDN)

Promise(MDN)

async function fnA() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('A')
    }, 3000)
  })
}
async function fnB() {
  return 'B'
}


async function test() {
  const v1 = await fnA()
  const v2 = await fnB()
  console.log(v1, v2)
}
test()  // 3秒后打印结果: A, B

如果将程序改写为下面这样:

async function test() {
  const v1 = fnA()
  const v2 = fnB()
  console.log(v1, v2)
}
test()  // 直接打印结果: Promise{<pending>},Promise{<pending>}

使用 koa应用生成器生成项目

npm i -g koa-generator

koa demo

通过 -V 查看版本,-h 查看帮助信息:

Usage: koa [options] [dir]

Options:

-h, --help          output usage information
-V, --version       output the version number
-e, --ejs           add ejs engine support (defaults to jade)
--hbs           add handlebars engine support
-H, --hogan         add hogan.js engine support
-c, --css <engine>  add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
--git           add .gitignore
-f, --force         force on non-empty directory

生成器生成如下文件和目录:

create : demo
create : demo/package.json
create : demo/app.js
create : demo/public
create : demo/routes
create : demo/routes/index.js
create : demo/routes/users.js
create : demo/views
create : demo/views/index.jade
create : demo/views/layout.jade
create : demo/views/error.jade
create : demo/bin
create : demo/bin/www
create : demo/public/stylesheets
create : demo/public/stylesheets/style.css

install dependencies:
> cd demo && npm install

run the app:
> SET DEBUG=demo:* & npm start

create : demo/public/javascripts
create : demo/public/images

路由及中间件

基本使用

路由(Router)就是根据不同 URL 地址,加载不同的页面实现不同的功能。

Koa中的路由需要安装路由模块来实现:

npm i -S koa-router

Github地址

const app = new Koa()
const router = new Router()

router.get('/', (ctx, next) => {
  ctx.body = 'Hello Koa!'
})

router.get('/about', (ctx, next) => {
  ctx.body = "这时一个测试网站"
})

// 启动路由
app.use(router.routes())
app.use(router.allowedMethods())  // 官方推荐用法,当所有路由中间件调用完后,根据 ctx.status 设置 response 响应头

app.listen(3000, () => {
  console.log(`服务运行于:http://localhost:3000`)
})

get传值

GET 传值通过 request 接收,有两种方法:

router.get('/about', (ctx, next) => {
  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

  const obj = {
    _url,
    _request,
    req_query,
    req_querystring,
    ctx_query,
    ctx_querystring
  }

  ctx.body = obj

})

浏览器输入:http://localhost:3000/about?name=ddd&age=18 可以查看效果:

{
  "_url": "/about?name=ddd&age=18",
  "_request": {
    "method": "GET",
    "url": "/about?name=ddd&age=18",
    "header": {
      "host": "localhost:3000",
      "connection": "keep-alive",
      "cache-control": "max-age=0",
      "upgrade-insecure-requests": "1",
      "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
      "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
      "accept-encoding": "gzip, deflate, br",
      "accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
    }
  },
  "req_query": {
    "name": "ddd",
    "age": "18"
  },
  "req_querystring": "name=ddd&age=18",
  "ctx_query": {
    "name": "ddd",
    "age": "18"
  },
  "ctx_querystring": "name=ddd&age=18"
}

动态路由

router.get('/page/:uid', async (ctx) => {
  let _params = ctx.params
  ctx.body = _params
})

当浏览器请求:http://localhost:3000/page/1 时,打印如下信息:

{"uid":"1"}

中间件

什么是中间件

中间件就是程序中可织入的,可重用的,与业务逻辑无关的各种组件。

中间件的功能包括:

Koa 应用可以使用如下几种中间件

1. 应用级中间件
const Koa = require('koa')
const Router = require('koa-router')

const app = new Koa()
const router = new Router()

app.use(async (ctx, next) => {
  console.log(new Date())
  await next()  // 这里必须有 next() 才能继续执行下面的中间件
})

router.get('/', (ctx, next) => {
  ctx.body = 'Hello Koa!'
})

router.get('/about', (ctx, next) => {
  ctx.body = '关于我'
})

// 启动路由
app.use(router.routes())
app.use(router.allowedMethods())  // 官方推荐用法,当所有路由中间件调用完后,根据 ctx.status 设置 response 响应头

app.listen(3000, () => {
  console.log(`服务运行于:http://localhost:3000`)
})

如上,程序先调用第一个中间件,打印当前时间,然后再执行后面的调用,如果这里没有写 next(),则不能调用路由,访问页面出错。

2. 路由中间件
router.get('/', async (ctx, next) => {
  console.log('来了老弟!')
  next()
})

router.get('/', (ctx, next) => {
  ctx.body = 'Hello Koa!'
})
3. 错误处理中间件
app.use(async (ctx, next) => {
  next()
  if (ctx.status == 404) {
    ctx.status = 404
    ctx.body = '您访问的页面好像丢了'
  }
})
4. 第三方中间件
// 支持访问静态文件
const path = require('path')
const static = require('koa-static')
const staticPath = './static'

app.use(static(path.join(__dirname, staticPath)))

// 解析 POST 中间件
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())

洋葱模型

洋葱模型
app.use((ctx, next) => {
  console.log('===== Start 1 =====')
  next()
  console.log('===== End 1 =====')
})

app.use((ctx, next) => {
  console.log('===== Start 2 =====')
  next()
  console.log('===== End 2 =====')
})

app.use((ctx, next) => {
  console.log('===== Start 3 =====')
  console.log('===== End 3 =====')
})

刷新页面,控制台打印:

===== Start 1 =====
===== Start 2 =====
===== Start 3 =====
===== End 3 =====
===== End 2 =====
===== End 1 =====

请求数据获取

GET获取数据

原生POST请求数据获取

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

// 解析上下文里的 POST 参数
function parsePostData(ctx) {
  return new Promise((resolve, reject) => {
    try {
      let postData = ''
      ctx.req.addListener('data', (data) => {
        postData += data
      })
      ctx.req.addListener('end', () => {
        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
}

app.use(async (ctx) => {
  console.log(ctx.url)
  console.log(ctx.method)
  if (ctx.url === '/form' && ctx.method === 'GET') {
    // GET 请求时,返回表单
    let html = `
      <h1>模拟表单提交</h1>
      <form method="POST" action="/form">
        <label for="user-name">用户名:</label>
        <input name="userName" type="text" id="user-name">
        <br>
        <label for="password">密码:</label>
        <input name="pwd" type="password" id="password">
        <br>
        <button type="submit">提交</button>
      </form>
    `
    ctx.body = html
  }
  else if (ctx.url === '/form' && ctx.method === 'POST') {
    console.log('yo')
    // POST 请求时,解析表单中的数据,并显示
    let postData = await parsePostData(ctx)
    ctx.body = postData
  }
  else {
    ctx.body = `<h1>好像哪里出了错误!</h1>`
  }
  
})

app.listen(3000, () => {
  console.log(`服务运行于:http://localhost:3000`)
})

koa-bodyparser中间件

使用koa-bodyparser中间件可以简化我们的操作,省去繁琐的配置。

安装

npm i -S koa-bodyparser

引入

const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const app = new Koa()

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

静态资源中间件

koa-static 中间件的作用

koa-static 中间件用于处理静态资源的请求

安装

npm i -S koa-static

Github

使用

const Koa = require('koa')
const path = require('path')
const static = require('koa-static')
const app = new Koa()
 
//设置静态资源的路径 
const staticPath = './static'
 
app.use(static(
  path.join( __dirname,  staticPath)
))

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

这时在 static 目录里新建一个 index.html 文件,随便写的内容,刷新页面,就能看到我们的新页面了。

cookie 和 session

Cookie

什么是 cookie

简单说就是服务器发送给用户浏览器并保存在本地的一小块数据,用来记录一些信息,方便下次访问时做一些事情。

百度百科

MDN

koa2 中 Cookie 的使用

设置Cookie的值
ctx.cookies.set(name, value, [options])

options 值可选,用来配置 cookie 的一些参数:

获取Cookie的值
ctx.cookies.get(name)

Session

什么是 session

session是一种保存在服务器上,用来记录客户状态的机制。

百度百科

Session 的工作流程

当浏览器访问服务器并发送第一次请求时,服务器端会创建一个 session 对象,生产一个类似于 key,value 的键值对,然后将 key(cookie) 返回到浏览器端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value) 。客户的信息都保存在 session 中。

使用 koa-session

安装

npm i -S koa-session

Github

引入
const session = require('koa-session')
设置
// 配置 session 中间件
app.keys = ['this is a key']
const CONFIG = {
  key: 'xxx',  // cookie key 默认值:koa:sess
  maxAge: 1000 * 60 * 60 * 24,  // 过期时间
  autoCommit: true,  // 自动提交头,默认:true
  overwrite: true,  // 是否可以覆盖,默认:true
  httpOnly: true,  // 只有服务端可以获取,默认:true
  signed: true,  // 签名,默认:true
  rolling: false,  // 强制重置 cookie,默认:false
  renew: false  // 会话快过期时更新,已始终保持用户的登录状态,默认:false
}
app.use(session(CONFIG, app))
使用
设置值  ctx.session.username = '东方未明'
获取值  ctx.session.username

示例:

const Koa = require('koa')
const Router = require('koa-router')
const session = require('koa-session')

const app = new Koa()
const router = new Router()

// 配置 session 中间件
app.keys = ['this is a key']
const CONFIG = {
  key: 'xxx',  // cookie key 默认值:koa:sess
  maxAge: 1000 * 60 * 60 * 24,  // 过期时间
  autoCommit: true,  // 自动提交头,默认:true
  overwrite: true,  // 是否可以覆盖,默认:true
  httpOnly: true,  // 只有服务端可以获取,默认:true
  signed: true,  // 签名,默认:true
  rolling: false,  // 强制重置 cookie,默认:false
  renew: false  // 会话快过期时更新,已始终保持用户的登录状态,默认:false
}
app.use(session(CONFIG, app))

router.get('/', (ctx) => {
  
  let name = ctx.session.username
  if (name) {
    ctx.body = `<h1>${name}你好!</h1>`
  }
  else {
    // 第一次访问时,设置session
    ctx.session.username = '东方未明'
    ctx.body = `<h1>欢迎来到武侠世界!</h1>`
  }

})

app.use(async (ctx, next) => {
  next()
  if (ctx.status == 404) {
    ctx.status = 404
    ctx.body = '您访问的页面好像丢了'
  }
})

// 启动路由
app.use(router.routes())
app.use(router.allowedMethods())  // 官方推荐用法,当所有路由中间件调用完后,根据 ctx.status 设置 response 响应头

app.listen(3000, () => {
  console.log(`服务运行于:http://localhost:3000`)
})
客户端cookie

Cookie 和 Session 区别

  1. cookie 数据存放在客户浏览器上,session 存在服务器上。
  2. cookie 安全性低于 session。
  3. session 会在一定时间内保存在服务器上,当访问增多时,会影响服务器性能,cookie不会。
  4. cookie 大小不超过4k,有的浏览器对 cookie 数有限制。

引擎模板(pug)

安装

npm i -S pug

npm i -S koa-views

pug中文文档

koa-views Github

pug 原名 Jade,是一款健壮、灵活、功能丰富的模板引擎,专门为 Node.js 平台开发。

koa-views 是一个支持模板呈现的中间件。

使用

项目目录中新建 views 目录,并新建 index.pug 文件:

项目目录

编写 index.pug

doctype html
html(lang='zh-Hans')
  head
    meta(charset='UTF-8')
    meta(name='viewport' content='width=device-width, initial-scale=1.0')
    meta(http-equiv='X-UA-Compatible' content='ie=edge')
    //- 这里得到传递来的参数
    title= pageTitle
    link(rel='stylesheet' href='./css/main.css')
  body
    h1 Hello Koa2
    p(class='test') 测试
    div(class='image-box')
      img(src='./img/mm.jpg' alt='美女')

注意上面引用静态资源时链接的写法,不是 ../static/css/main.css 而是 ./css/main.css 这时因为我们用 koa-static 中间件来处理静态资源的请求,这里只需写我们设置的默认地址下的地址就可以了。

const Koa = require('koa')
const Router = require('koa-router')
const path = require('path')
const views = require('koa-views')  // 引入模板呈现中间件
const static = require('koa-static')  // 引入静态资源中间件
const viewsPath = './views'  // 模板默认地址
const staticPath = './static'  // 静态资源默认地址

const app = new Koa()
const router = new Router()

app.use(views(path.join(__dirname, viewsPath), {
  extension: 'pug'   // 视图默认扩展名
}))

router.get('/', async (ctx, next) => {
  await ctx.render('index', {
    pageTitle: '首页'   // 传递的参数
  })
})

app.use(static(path.join(__dirname, staticPath)))

// 加载路由
app.use(router.routes())
app.use(router.allowedMethods())

app.listen(3000, () => {
  console.log(`服务运行于:http://localhost:3000`)
})
上一篇下一篇

猜你喜欢

热点阅读