快速开始
安装
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{},Promise{}
使用 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 add stylesheet 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 接收,有两种方法:
- query:返回格式化的参数对象
- querystring:返回请求字符串
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获取数据
- 从上下文中直接获取
ctx.query
ctx.querystring
- 从上下文的
request
对象中获取- ctx.request.query
- ctx.request.querystring
原生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 = `
模拟表单提交
`
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 = `好像哪里出了错误!
`
}
})
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 的一些参数:
- maxAge:一个数字,cookie的保留时长,单位豪秒,优先级高于 expires
- expires:失效时间,为GMT格式(Wdy, DD-Mon-YYYY HH:MM:SS GMT),如果不设置或设置为以前的日期,则cookie会被立刻删除
- signed:签名,布尔值
- path:路径,默认是:“/”
- domain:域名
- secure:安全
- httpOnly:服务器可访问,默认是 true
- overwrite:是否覆盖以前的同名 cookie,默认是 false
获取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 = `${name}你好!
`
}
else {
// 第一次访问时,设置session
ctx.session.username = '东方未明'
ctx.body = `欢迎来到武侠世界!
`
}
})
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 和 Session 区别
- cookie 数据存放在客户浏览器上,session 存在服务器上。
- cookie 安全性低于 session。
- session 会在一定时间内保存在服务器上,当访问增多时,会影响服务器性能,cookie不会。
- 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`)
})