Koa 以及中间件学习笔记
简单开始
级联
next() 暂停当前函数的执行,进行下面函数的执行,然后会到上游next函数执行处,继续向下执行。
const Koa =require('koa')
const app = new Koa()
app.use(async (ctx, next) =>{
console.log(1)
await next()
const rt = ctx.response.get('X-Response-Time')
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
console.log(2)
})
app.use(async (ctx, next) =>{
console.log(3)
const start =Date.now()
await next()
const ms= Date.now() - start
ctx.set('X-Response-Time',`${ms}ms`)
console.log(4);
})
app.use(async ctx =>{
ctx.body='Hello world'
console.log(5)
})
app.listen(3000)
// 1 3 5 4 2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
属性
app的属性和方法
app.env
环境变量 默认使NODE_ENV development
app.proxy
//设置代理
app.subdomainOffset
可以监听多个端口
app.callback()
将方法用于 http.createServer https.createServer 或者connect 和express程序
app.use(function)
将给定的中间件方法添加到此应用程序
app.keys
设置Cookie 密匙
app.context
从外部直接向ctx 内部添加属性
app.context.db = db();
app.use(async ctx => {
console.log(ctx.db);
});
2
3
4
5
错误处理
通过监听 error 事件进行事件处理 app.on('error', err , ctx=> { //ctx 可以继续向下传递 log.error('server error', err) //错误日志 });
ctx 属性
基本属性
ctx.req
ctx.res node 的请求与相应对象
ctx.responce
ctx.request koa 的对象
ctx.state 推荐的进行变量绑定的地方
ctx.app app对象
ctx.app.emit 触发on的绑定事件
ctx.cookies.set 设置cookie
ctx.cookies.get 获取cookis
ctx.throw([status], [msg], [properties]) 通常使用户的错误 而不是服务器的错误 http-errors
ctx.assert(value, [status], [msg], [properties]) 用于断言 当第一个值为false的时候 第二值为错误码 第三个值使message http-assert
Request 别名
以下访问器和 Request 别名等效:
ctx.header 请求的标识头 可设置
ctx.headers ==上面
ctx.method 请求方法 可设置
ctx.url 请求的url 可设置
ctx.originalUrl 获取请求原始URL
ctx.origin 获取URL的来源,包括 protocol 和 host。
ctx.href
ctx.path
ctx.path=
ctx.query
ctx.query=
ctx.querystring
ctx.querystring=
ctx.host
ctx.hostname
http://localhost:3000 -------origin 常用
http://localhost:3000/apple?abc=11111 -------href
/apple?abc=11111 -------originalUrl
/apple -------path 常用
/apple?abc=11111 -------url
{ abc: '11111' } -------query 常用
abc=11111 -------querystring
localhost:3000 -------host
localhost -------hostname
2
3
4
5
6
7
8
9
- ctx.fresh 检查缓存是否新鲜 也就是内容
没有改变
。 在设置一个或多个这些响应头后应该引用它。 - ctx.stale 以上面相反
- ctx.socket request.socket 返回请求套接字。
- ctx.protocol 返回请求协议,“https” 或 “http”。当 app.proxy 是 true 时支持 X-Forwarded-Proto。
- ctx.secure 通过 ctx.protocol == "https" 来检查请求是否通过 TLS 发出。
- ctx.ip 返回请求的IP
- ctx.ips 返回转发过后的多个IP
- ctx.subdomains 返回子域名 根据 subdomainsoffset偏移量试着
- ctx.is() 检查传入请求是否包含 Content-Type 头字段, 并且包含任意的 mime type。 如果没有请求主体,返回 null。 如果没有内容类型,或者匹配失败,则返回 false。 反之则返回匹配的 content-type。
- ctx.accepts() request.accepts(types) 通过类型检查 可以适用switch设置
- ctx.acceptsEncodings() request.acceptsEncodings(encodings) encodings检查
- ctx.acceptsCharsets() request.acceptsCharsets(charsets) 编码类型检查
- ctx.acceptsLanguages() request.acceptsLanguages(langs) 语言类型检查
- ctx.get() request.get(field) 返回请求标头。
Response 别名
以下访问器和 Response 别名等效:
- ctx.body
- ctx.body=
string 写入
Buffer 写入
Stream 管道
Object || Array JSON-字符串化
null 无内容响应
2
3
4
5
- ctx.status 状态码
- ctx.status=
- ctx.message 信息
- ctx.message=
- ctx.length= 长度
- ctx.length
- ctx.type= 获取响应 Content-Type 不含参数 "charset"。
- ctx.type
- ctx.headerSent 检查是否已经发送了一个响应头。 用于查看客户端是否可能会收到错误通知。
- ctx.redirect() response.redirect(url, [alt])
- ctx.attachment()将 Content-Disposition 设置为 “附件” 以指示客户端提示下载。(可选)指定下载的 filename 和部分 参数。
- ctx.set() 设置响应标头 field 到 value: 用一个对象设置多个响应标头fields:
- ctx.append() 用值 val 附加额外的标头 field。
- ctx.remove() 移除表头
- ctx.lastModified= 将 Last-Modified 标头返回为 Date, 如果存在。 检查最后的更改事件
- ctx.etag= 设置etag 头部
- response.is(types...) 。这对于创建操纵响应的中间件特别有用。
html-minifier
,可以削减除流之外的所有HTML响应。 - response.vary(field) 查看在 field 上变化。
- response.flushHeaders() 刷新任何设置的标头,并开始主体。
缓存
使用 HTTP 缓存:Etag, Last-Modified 与 Cache-Control Cache-Control 响应头表示了资源是否可以被缓存,以及缓存的有效期。
- no-cache 为本次响应不可直接用于后续请求(在没有向服务器进行校验的情况下)
- no-store 为禁止缓存(不得存储到非易失性介质,如果有的话尽量移除,用于敏感信息)
- private为仅 UA 可缓存
- public为大家都可以缓存。
- 可以添加过期时间 max-age Etag 响应头标识了资源的版本,此后浏览器可据此进行缓存以及询问服务器。
- Etag 响应头字段表示资源的版本
- 浏览器在发送请求时会带 If-None-Match 头字段, Last-Modified 响应头标识了资源的修改时间,此后浏览器可据此进行缓存以及询问服务器。
- if-modified-since 在请求头中 时间戳
- 如果没有过过期时间则可以直接适用缓存 返回304 而不返回任何资源
- 否则返回一个Last-Modified', new Date().toString() 设置新时间
koa 中间件
- Keygrip是一个node.js模块,用于通过轮换凭证系统对数据(如cookie或URL)进行签名和验证,其中可以添加新服务器密钥并定期删除旧服务器密钥,而不会使客户端凭据无效。
- html-minifier 缩小html 大小
- koa-router 路由
- koa-bodyparser 解析post
- koa-session session 中间件
- koa-logger koa 使用日志打印的中间件
koa-router
路由使用
/*
* @Author: yu-lei
* @Date: 2019-08-22 20:02:15
* @Last Modified by: yu-lei
* @Last Modified time: 2019-08-26 11:22:21
*/
/**
* 包区域
*/
const koa =require('koa')
const koaRouter = require('koa-router')
const koaBodyparser = require('koa-bodyparser')
/**
* 定义区域
*/
const app =new koa()
const router = new koaRouter()
/**
* 文件区域
*/
//路由
const userRoutes = require('./routers/users')()
const homeRoutes = require('./routers/homes')()
/**
* 中间件
*/
app.use(koaBodyparser())
app.use(router.routes())
app.use(homeRoutes.routes())
app.use(userRoutes.routes())
app.use(router.allowedMethods()) //开启所有的请求方法
/**
* 服务器
*/
app.listen(3000, () =>{
console.log("服务器已经开启!")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
路由匹配方式
router.all('/*' , async (ctx,next) =>{
console.log(ctx.url)
// 决绝特殊访问服务
// 搜索引擎优化
//roubat
// 过滤服务
await next()
})
router.get()// get|put|post|patch|delete|del|all
router.regiest('path','GET',(ctx.next)=>{}) // 注册方法
2
3
4
5
6
7
8
9
10
路由的三种传递参数方式
1 通过动态router 传递
通过ctx.params.id
获取
router.get('/home/:id',async (ctx,next) =>{
ctx.body="<h1>home route</h1>"
console.log(ctx.params.id) //
})
2
3
4
5
6
2 通过query 字符串传递
通过ctx.query.参数名称获取
router.get('/home',async (ctx,next) =>{
ctx.body="<h1>home route</h1>"
console.log(ctx.query.id) //
})
2
3
4
5
3 通过post 传递
通过 koa-bodyparser
内的 ctx.request.body
获取
router.post('/home',async (ctx) =>{
console.log(ctx.request.body)
ctx.body=ctx.request.body
// console.log(ctx.request.body)
})
2
3
4
5
redirect
router.redirect('从那个路由',’跳转到那个路由‘,状态码)
// redirect 可能不需要匹配prefex 和父组件也会 匹配到路由跳转
2
3
use 嵌套路由
const userRouter = new koaRouter({
prefix:'/user'
})
userRouter.get('/admin',async ctx=>{
//todo
})
//中间件使用方法
router.use('/home',userRouter.routes(),userRouter.allowedMethods({配置}))
//请求地址为
// /home/user/admin 显示嵌套的父级路由 然后是子集路由的prefix 然后是接口
2
3
4
5
6
7
8
9
10
11
router.param(param, middleware)
所有带有id 参数的路由全部需要先经过这个路由
const router = new koaRouter({
prefix:'/home'
}) //子路由
router
// 所有带有id 参数的路由全部需要先经过这个路由
.param('id',async (id, ctx, next) =>{
console.log(ctx.path,'param');
await next()
})
.get('/user/:id' , async ctx =>{
console.log(1,ctx.params.id)
})
.get('/haha/:id' , async ctx =>{
console.log(2,ctx.params.id)
})
.redirect('/abc/:id','/haha/1',303)
return router
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22