最近由於開發一個本身的博客網站,學習了koa2的搭建,寫了一些本身認爲比較重要或須要知道的koa2中間件做用和使用場景。javascript
路由中間件java
npm i koa-router
須要注意的是引入的koa-router是一個方法,引入後須要執行這個方法。node
const Koa = require('koa'); const app = new Koa(); const router = require('koa-router')(); // 配置路由url // 默認url router.get('/', async (ctx, next) => { ctx.body = 'Hello World'; }); // 自定義url router.get('/hello/:name', async (ctx, next) => { var name = ctx.params.name; ctx.response.body = \`<h1>Hello, ${name}!</h1>\`; }); // 註冊路由 app.use(router.routes(), router.allowedMethods());
也能夠按需引入並註冊路由,可註冊多個路由。npm
經過ctx.query獲取參數json
經過ctx.request.body獲取參數api
經過ctx.params獲取參數跨域
首先引入nodejs中的fs模塊,使用fs的readdirSync方法獲取到指定目錄的全部文件名,遍歷引入路由模塊並註冊。數組
const fs = require('fs'); // fs.readdirSync 獲取指定目錄下的全部文件名稱,遍歷引入路由模塊並註冊 fs.readdirSync('./routes').forEach(route=> { let api = require(\`./routes/${route}\`); app.use(api.routes(), api.allowedMethods()); });
設置已經初始化的路由器實例的路徑前綴cookie
router.prefix('/user'); router.post('/login', function(ctx, next) { ... }); // 實際路徑 /user/login
使用場景:咱們一般須要經過驗證用戶和用戶權限來斷定用戶是否能使用該接口,若是在每一個接口都寫一次驗證很是麻煩且很差維護。這時咱們就須要路由中間件先進行驗證,再執行下面操做。 session
router.use的第一個參數爲一個路徑或者由多個須要使用中間件的路徑組成的數組(須要注意的是,若是路由設置了url前綴,須要在設置前綴後註冊中間件,參數中的url不須要設置前綴)。
router.use的第二個參數爲函數,函數傳遞ctx和next兩個參數,可經過ctx進行權限驗證後,判斷是否執行next調用接口。這裏特別須要注意的是函數使用next的時候須要添加await,若是不添加,在調用接口前,接口就會返回結果,前臺則沒法獲取到數據。
// this is wrong app.use(function (ctx, next) { ctx.set("Access-Control-Allow-Origin", "\*"); next(); }); // this is right app.use(async function (ctx, next) { ctx.set("Access-Control-Allow-Origin", "\*"); await next(); });
處理post請求時,咱們會遇到一個問題,不管是node的request對象仍是koa的request對象,都沒辦法解析request的body,咱們就須要下載並引入一個解析body的中間件koa-bodyparser,koa-bodyparser的具體配置詳見下面的說明,這裏咱們直接放入使用方式。
// 引入路由文件 const index = require('./routes/index.js'); const user = require('./routes/user.js'); // 引入解析request.body的中間件 const bodyparser = require('koa-bodyparser'); // 註冊bodyparser,須要注意,bodyparser的註冊必定要在router路由註冊以前 app.use(bodyparser({ enableTypes:\['json', 'form', 'text'\] })); ... // 註冊routes app.use(index.routes(), index.allowedMethods()); app.use(user.routes(), user.allowedMethods());
如上所述,koa-bodyparser用於解析request.body,由於node和koa的request沒法解析body。
npm i koa-bodyparser
const bodyparser = require('koa-bodyparser');
在註冊運行時,bodyparser方法中可傳入對象,做相應配置。
- enableTypes:解析器只在配置了enableTypes時解析請求類型,默認是['json', 'form']。
- encoding:請求編碼,默認是utf-8。
- formLimit:urlencoded body的imit若是主體最終大於此限制,則返回一個413錯誤代碼。默認是56 kb。
- jsonLimit:json主體的限制。默認是1 mb。
- textLimit:文本主體的限制。默認是1 mb。
- strict:當設置爲true時,JSON解析器將只接受數組和對象。默認是正確的。參見正文中的嚴格模式。在嚴格模式下,ctx.request。body老是一個對象(或數組),這避免了不少類型判斷。但文本正文老是返回字符串類型。
- detectJSON:自定義json請求檢測函數。默認爲null。
app.use(bodyparser({ detectJSON: function (ctx) { return /\\.json$/i.test(ctx.path); } }));
- extendTypes:支持擴展類型
app.use(bodyparser({ extendTypes: { json: \['application/x-javascript'\] // 解析application/x-javascript 類型 做爲JSON字符串 } }));
- onerror:支持自定義錯誤句柄,若是koa-bodyparser拋出一個錯誤,您能夠自定義響應以下:
app.use(bodyparser({ onerror: function (err, ctx) { ctx.throw('body parse error', 422); } }));
- disableBodyParser:能夠經過設置ctx動態禁用body解析器。disableBodyParser = true。
app.use(async (ctx, next) => { if (ctx.path === '/disable') ctx.disableBodyParser = true; await next(); }); app.use(bodyparser());
請求響應監聽日誌
npm i koa-logger
~~// 引入日誌中間件 const logger = require('koa-logger'); // 註冊日誌中間件 app.use(logger()); ~~
用於Koa的簡單會話中間件。默認爲基於cookie的會話,並支持外部存儲。
咱們知道,http協議是無狀態的,當用戶進行登陸後,並不會保存帳戶密碼,若是咱們須要維持用戶的登陸狀態,就須要使用一些方法。目前主流的用戶認證方法有基於token和基於session兩種方式。
基於token的認證可使用koa-jwt中間件,基於session的認證則使用標題的koa-session。
npm i koa-session
const CONFIG = { key: 'koa:sess', /\*\* (string) cookie key (default is koa:sess) \*/ /\*\* (number || 'session') maxAge in ms (default is 1 days) \*/ // 狀態保存最大時間,默認爲一天 maxAge: 86400000, autoCommit: true, /\*\* (boolean) 自動保存頭部 (default true) \*/ overwrite: true, /\*\* (boolean) 可否覆蓋 (default true) \*/ httpOnly: true, /\*\* (boolean) httpOnly or not (default true) \*/ signed: true, /\*\* (boolean) signed or not (default true) \*/ /\*\* (boolean) 強制在每一個響應上設置會話標識符cookie。過時將重置爲原始maxAge,從新設置過時倒計時。 (default is false) \*/ rolling: false, /\*\* (boolean) 當會話快過時時續訂會話,這樣咱們能夠始終保持用戶登陸。(default is false)\*/ renew: false, }; // 若是你全部都爲默認配置,則不須要傳遞配置參數,app.use(session(app))便可 app.use(session(sessionConfig, app));
註冊後能夠經過上下文ctx找到session屬性,下面代碼將用戶信息存入session屬性中,並建立key和value
user.js
// 用戶登陸
static async login(ctx, next) {
const data = ctx.request.body const schema = Joi.object().keys({ username: Joi.string().required(), password: Joi.string().required(), }) let result = Joi.validate(data, schema) // 若是有字段類型錯誤 if(result.error) { return ctx.response.body = { status: 400, msg: result.error.details}; } let { username, password } = result.value // 驗證事後的數據 // 查找是否有該用戶 const userInfo = await usersModel.findByName(username) // 若是有該用戶,繼續驗證密碼是否正確 if (userInfo) { const userInfo2 = await usersModel.findOne({ username, password }) if (userInfo2) { ctx.response.body = {state: 200, msg: '登陸成功'} // 設置session ctx.session.userInfo = userInfo2 } else { ctx.response.body = {state: 410, msg: '密碼錯誤'} } // 若是沒有該用戶,返回結果 } else { ctx.response.body = {state: 410, msg: '該用戶不存在'} } return ctx.response.body
}
koa-router路由中間件中驗證session,這裏須要注意的是next()方法前必定要使用await,否則程序不會等待next()方法執行。
export const verifyUser = async (ctx, next) => {
if (ctx.session.userInfo) { await next() } else { return ctx.response.body = { state: 401, msg: '無權限訪問' } }
}
用於解決跨域問題
npm install koa2-cors
app.use(cors())