1、koa框架
简介
Koa是基于Node.js的下一代web框架;该框架除了本身koa库之外,还包括一些列家族中间件,如koa-body,koa-jwt,koa-route,koa-router等。koa通过使用use方法加载这些中间件,每个中间件接收两个参数,ctx对象和next函数,通过调用next将执行权交给下一个中间件。
Koa使用
const Koa = require('koa'); // 创建一个Koa对象 // 对于任何请求,app将调用该异步函数处理请求: let start = new Date(); await next(); let ms = new Date() - start; console.log(`${ctx.url}${JSON.stringify(ctx.query)} - ${ms} ms`); }); // 错误处理,如token超时 app.use((ctx, next) => { return next().catch((err) => { // console.warn("Token Authentication", err); // Print the stack trace if (err.status === 401) { ctx.status = 401; ctx.body = 'Protected resource, use Authorization header to get access\n'; // todo.. 可以ctx.body返回错误信息给用户 return; } else { throw err; } }); });
app.listen(3000);
|
其他以上代码的参数解析如下:
ctx:由koa传入的封装了request和response的变量,我们可以通过它访问request和response;
next:是koa传入的将要处理的下一个异步函数。
await next():处理下一个异步函数,由async标记的函数称为异步函数,在异步函数中,可以用await调用另一个异步函数。
Koa 中 GET传值通过request接收,有两种方式: query 和 querystring
query:返回的是参数对象。 {name: 'jack', age: 12}
querystring:返回的是请求字符串。 name=jack&age=12
2、中间件
2.1 koa-router
koa-router是一个路由中间件,负责处理URL的映射。
1)加载koa-router
const Koa = require('koa'); // 1. 直接调用的方式 const router = require('koa-router')(); // 2. 单独创建router的实例 // const Router = require('koa-router'); const router = new Router({ prefix: '/api' // 给url添加前缀 }); router.get('/', async ctx => { ctx.body = 'Hello Router'; }) // 启动路由 app.use(router.routes()) .use(router.allowedMethods()) app.listen(3000, err => { if (err) throw err; console.log('runing...'); }); |
2)路由
router.get('/get/user', async (ctx, next) => { console.log(111) await next(); }) router.put('/put/user', async (ctx, next) => { console.log(222) await next(); }) router.post('/post/user', async ctx => { console.log(333) ctx.body = 'Hello' }) |
如果在koa已经处理了next,则路由中不需要再次处理,因为koa会自动条用next处理下一个异步函数。
2.2 koa-body
koa-body可以实现文件上传,同时可以让koa获取post请求的参数。用于替换koa-bodyparser(处理post请
求)和koa-multer(处理图片/文件上传)
1)加载koa-body
const koaBody = require('koa-body'); const app = new koa(); app.use(koaBody({ multipart:true, // 支持文件上传 encoding:'gzip', formidable:{ uploadDir:path.join(__dirname,'public/upload/'), // 设置文件上传目录 keepExtensions: true, // 保持文件的后缀 maxFieldsSize:2 * 1024 * 1024, // 文件上传大小 onFileBegin:(name,file) => { // 文件上传前的设置 // Todo... }, } })); |
2)使用koa-body
router.post('/api/file',async (ctx)=>{ let _files = ctx.request.files; let _para = ctx.request.body; ctx.body = JSON.stringify(ctx.request.files); }); |
3)参数
参数名 | 描述 | 类型 | 默认值 |
patchNode | 将请求体打到原生 node.js 的ctx.req中 | Boolean | false |
patchKoa | 将请求体打到 koa 的 ctx.request 中 | Boolean | true |
jsonLimit | JSON 数据体的大小限制 | String / Integer | 1mb |
formLimit | 限制表单请求体的大小 | String / Integer | 56kb |
textLimit | 限制 text body 的大小 | String / Integer | 56kb |
encoding | 表单的默认编码 | String | utf-8 |
multipart | 是否支持 multipart-formdate 的表单 | Boolean | false |
urlencoded | 是否支持 urlencoded 的表单 | Boolean | true |
text | 是否解析 text/plain 的表单 | Boolean | true |
json | 是否解析 json 请求体 | Boolean | true |
jsonStrict | 是否使用 json 严格模式,true 会只处理数组和对象 | Boolean | true |
formidable | 配置更多的关于 multipart 的选项 | Object | {} |
onError | 错误处理 | Function | function(){} |
stict | 严格模式,启用后不会解析 GET, HEAD, DELETE 请求 | Boolean | true |
2)formidable 的相关配置参数
参数名 | 描述 | 类型 | 默认值 |
maxFields | 限制字段的数量 | Integer | 1000 |
maxFieldsSize | 限制字段的最大大小 | Integer | 2 * 1024 * 1024 |
uploadDir | 文件上传的文件夹 | String | os.tmpDir() |
keepExtensions | 保留原来的文件后缀 | Boolean | false |
hash | 如果要计算文件的 hash,则可以选择 md5/sha1 | String | false |
multipart | 是否支持多文件上传 | Boolean | true |
onFileBegin | 文件上传前的一些设置操作 | Function | function(name,file){} |
2.3 Koa-jwt与koawebtoken
Koa-jwt提供路由权限控制,它会对具有权限控制资源的请求进行检查,同时可以设置不需要检查的指定接
口,设定之后权限检查便会绕过这些接口。
koawebtoken用于签发和解析token。
签发:jwt.sign(payload, secretOrPrivateKey, [options, callback]),
参数如下:
payload:必须是一个object, buffer或者string。请注意, expiresIn只有当payload是object字面量时才可以设置。
secretOrPrivateKey:包含HMAC算法的密钥或RSA和ECDSA的PEM编码私钥的string或buffer。
options:
- algorithm:加密算法(默认值:HS256)
- expiresIn:以秒表示或描述时间跨度zeit / ms的字符串。如60,"2 days","10h","7d",Expiration time,过期时间
- notBefore:以秒表示或描述时间跨度zeit / ms的字符串。如:60,"2days","10h","7d"
- audience:Audience,观众
- issuer:Issuer,发行者
- jwtid:JWT ID
- subject:Subject,主题
- noTimestamp
- Header
options参数可以缩写,expiresIn,notBefore,audience,subject,issuer的缩写形式是exp,nbf,aud,sub和iss。exp,nbf,iat是NumericDate类型。
jwt.verify(token,secretOrPublicKey,[options,callback])
验证token的合法性
1)使用
const Koa = require('koa') const Router = require('koa-router') const jwt = require('jsonwebtoken'); const koaBody = require('koa-body') const koaJwt = require('koa-jwt') //路由权限控制 const app = new Koa() const router = new Router() //秘钥 const jwtSecret = 'jwtSecret' const tokenExpiresTime = 1000 * 60 * 60 * 24 * 7 // Custom 401 handling if you don't want to expose koa-jwt errors to users app.use(function(ctx, next){ return next().catch((err) => { if (401 == err.status) { ctx.status = 401; ctx.body = 'Protected resource, use Authorization header to get access\n'; } else { throw err; } }); }); app.use(koaJwt({ secret: jwtSecret }).unless({ // 以下接口不验证,其他接口都需要token验证(是否超时),jwt自动实现 path: [ /\/user\/login/, /\/user\/register/, /\/user\/setPwd/, /\/admin\/login/, /\/admin\/setPwd/, ] })); router.post('/user/login', koaBody(), (ctx) => { const user = ctx.request.body if (user && user.name){ // Todo... e.g: get user.id from db let payload = { iss: jwtSecret, id: user.id, type: USER_TYPE.user } const token = jwt.sign(payload, jwtSecret, {expiresIn: '12h'}); ctx.body = { code:1, msg: 'login success!', token } }else { ctx.body = { code:-1, msg: 'login fail!' } } }) router.get('/userInfo', ctx => { let token = ctx.header.authorization ctx.body = { token:token, user:ctx.state.user } //获取payload数据 let payload = jwt.verify(token.split(' ')[1], jwtSecret); console.log(payload) }) app.use(router.routes()) app.use(router.allowedMethods()) app.listen(3000, () => { console.log('app listening 3000...') }) |