1. Koa的安裝和搭建:
1.1 項(xiàng)目初始化:
npm init
會生成配置文件package.json刃永,用于管理項(xiàng)目中用到的一些安裝包。
1.2 安裝Koa:
npm install koa --save
1.3 編寫app.js谨垃,啟動服務(wù):
簡單編寫一個app.js應(yīng)用程序:
const koa = require('koa');
const app = new koa();
app.use(async (ctx, next)=>{
ctx.response.body = '<h1>Hello World</h1>';
});
app.listen(3000, ()=>{
console.log('server is running at port 3000.');
})
node app.js
啟動服務(wù),訪問本地 http://localhost:3000會看到Hello World。
當(dāng)然便于項(xiàng)目的調(diào)試和服務(wù)在線運(yùn)行的穩(wěn)定影斑,建議使用pm2
啟動Koa服務(wù)瞬浓。
2. Context對象:
context成為‘上下文’初婆,在Koa中Nodejs的原生request和response對象都封裝到了context對象中,Koa應(yīng)用程序的每個請求都將創(chuàng)建一個context猿棉,并在中間件中作為參數(shù)被引用磅叛。
下面列舉一些經(jīng)常用到的context屬性值:
2.1 ctx.request
-
ctx
是context的簡寫,ctx.request
是Koa的request對象萨赁,看一段代碼宪躯,看一下GET請求數(shù)據(jù)是怎么獲取和解析的:
const koa = require('koa');
const app = new koa();
app.use(async (ctx, next)=>{
ctx.response.body = {
url: ctx.request.url, //獲取請求的URL
query: ctx.request.query, //獲取get請求的解析數(shù)據(jù)
querystring: ctx.request.querystring //獲取原始get請求的字符串
}
})
node app.js
啟動應(yīng)用,訪問http://localhost:3000/?search=koa&keywords=context
位迂,便可以看到返回的響應(yīng):
{
"url": "/?search=koa&keywords=context",
"query":{"search":"koa", "keywords":"context"},
"querystring":"search=koa&keywords=context"
}
- 有GET請求數(shù)據(jù)的獲取访雪,比然有POST數(shù)據(jù)的獲取和解析详瑞,原生nodejs中獲取POST請求的方式比較繁瑣(可自行搜索一下,其實(shí)不復(fù)雜)臣缀,這里直接引用
koa-bodyparser
中間件:
npm install koa-bodyparser --save
安裝該中間件坝橡,下面通過一個簡單的表單提交測試koa-bodyparser
如何獲取post數(shù)據(jù)的:
const koa = require('koa');
const bodyParser = require('koa-bodyparser');
const app = new koa();
app.use(bodyParser());
app.use(async (ctx, next)=>{
//解析后的post數(shù)據(jù)會存儲在ctx.request.body中,如果沒有數(shù)據(jù)則為空對象
ctx.body = ctx.request.body;
})
app.listen(3000, ()=>{
console.log('server is running at port 3000');
})
后面結(jié)合router路由精置,通過一個form表單來測試一下效果计寇。
2.2 ctx.response
ctx.response是Koa的response對象,其中包含了幾個常用的屬性:
-
ctx.response.body
:返回給用戶的響應(yīng)主體脂倦。 -
ctx.response.status
:設(shè)置響應(yīng)狀態(tài)碼(如200番宁、404、500等)赖阻。在實(shí)際開發(fā)中蝶押,除了設(shè)置一個請求的響應(yīng)主體外,往往還要設(shè)置響應(yīng)狀態(tài)碼火欧。 -
ctx.response.type
:設(shè)置響應(yīng)的Content-Type
棋电,顯示地設(shè)置Content-Type是因?yàn)闉g覽器默認(rèn)地Content-Type是text/plain
,如果Content-Type不對會發(fā)生解析錯誤苇侵。如果響應(yīng)內(nèi)容是HTML赶盔,則設(shè)置為ctx.response.type='html'
;如果響應(yīng)地是png圖片榆浓,則ctx.response.type='image/png'
于未。
2.3 ctx.state
ctx.state
是推薦地命名空間,用于通過中間件傳遞信息和前端視圖陡鹃。例如koa-views
這些渲染Views視圖層地中間件會默認(rèn)把ctx.state
里面地屬性作為視圖模板的參數(shù)傳入烘浦。
2.4 ctx.cookies
ctx.cookies
用于獲取和設(shè)置Cookie。
ctx.cookies.get(name, [options]); //獲取Cookie
ctx.cookies.set(name, value, [options]); //設(shè)置Cookie
其中options配置如下:
- maxAge: /ms為單位的過期時間
- signed: Cookie簽名值
- expires: Cookie過期的Date
- path: Cookie路徑杉适,默認(rèn)/
- domain: Cookie域名
- secure: 安全Cookie谎倔,只能使用https協(xié)議
- httpOnly: true則Cookie無法被javascript獲取到
- overwrite: 布爾值,是否覆蓋以前設(shè)置的同名Cookie猿推,默認(rèn)false
2.5 ctx.throw
ctx.throw
用于拋出錯誤片习,把錯誤信息返回給用戶:
app.use(async (ctx)=>{
ctx.throw(500); //將響應(yīng)500錯誤
})
3. Koa中間件:
3.1 理解中間件的概念:
先來看下面這段代碼:
app.use(async (ctx, next)=>{
console.log(ctx.method, ctx.host+ctx.url); //打印請求方法、主機(jī)名蹬叭、URL
await next();
ctx.body = 'Hello World';
})
上述代碼可以打印日志藕咏,返回'Hello World',其實(shí)可以將其中打印日志的部分功能抽象成一個logger函數(shù):
const logger = async function(ctx, next){
console.log(ctx.method, ctx.host+ctx.url);
await next();
}
app.use(logger); //使用app.use()加載中間件
app.use(async (ctx, next) => {
ctx.body = 'Hello World';
})
像上面抽象出來的logger函數(shù)就是中間件秽五,通過app.use()來加載中間件孽查。
3.2 koa-bodyparser中間件:
對于post請求的數(shù)據(jù)獲取,原生nodejs使用了req對象監(jiān)聽data事件并將其拼接得到坦喘,比較繁瑣盲再。而koa-bodyparser
可以直接把post數(shù)據(jù)解析到ctx.request.body中西设,先安裝npm install koa-bodyparser --save
,然后通過一個表單提交來測試一下:
const koa = require('koa');
const bodyParser = require('koa-bodyparser');
const app = new koa();
app.use(bodyParser());
app.use(async (ctx, next)=>{
if(ctx.url == '/' && ctx.request.method == 'GET'){
ctx.request.type = 'html';
let html = `
<h2>登錄</h2>
<form action="/" method="POST">
<p>用戶名:</p>
<input name="name" /></br>
<p>密碼:</p>
<input name="password" type="password" /></br>
<button type="submit">Submit</button>
</form>
`
ctx.body = html;
}else if(ctx.url=='/' && ctx.request.method=='POST'){
let postData = ctx.request.body;
ctx.body = postData;
}
})
提交表單數(shù)據(jù)后答朋,將會看到bodyParser
解析的post數(shù)據(jù)對象贷揽。
3.3 koa-router中間件:
上面登錄表單的例子通過ctx.url判斷路徑,通過ctx.request.method判斷請求方式梦碗,然而這種手動判斷路由的方法禽绪,隨著后面各種各樣的業(yè)務(wù)增多,會嚴(yán)重影響代碼的可讀性和可維護(hù)性洪规,借助于koa-router
中間件印屁,能清晰簡單的處理各種請求路由,先安裝npm install koa-router --save
斩例,具體用法如下面代碼:
const koa = require('koa');
const bodyParser = require('koa-bodyparser');
const router = require('koa-router')();
const app = new koa();
app.use(bodyParser());
router.get('/', (ctx, next)=>{
// 登陸頁雄人,省略
});
router.post('/', (ctx, next)=>{
let postData = ctx.request.body;
ctx.body = postData;
});
app.use(router.routes()); //加載router中間件
app.use(router.allowedMethods()); //對異常狀態(tài)碼的處理
上面的代碼中,直接通過router.get('uri')
和router.post('uri')
來處理GET和POST請求的uri樱拴,不需要再進(jìn)行手動判斷了柠衍。
3.3.1 koa-router獲取GET請求的傳值:
koa-router
將原生的nodejs的request封裝在ctx中:
- ctx.query:返回的是格式化好的參數(shù)對象
- ctx.querystring:返回的是請求字符串
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
router.get('/', function (ctx, next) {
ctx.body="Hello koa";
})
router.get('/newscontent',(ctx,next)=>{
let url =ctx.url;
//從request 中獲取GET 請求
let request =ctx.request;
let req_query = request.query;
let req_querystring = request.querystring;
//從上下文中直接獲取
let ctx_query = ctx.query;
let ctx_querystring = ctx.querystring;
ctx.body={
url,
req_query,
req_querystring,
ctx_query,
ctx_querystring
}
});
app.use(router.routes()); //作用:啟動路由
app.use(router.allowedMethods()); //作用: 當(dāng)請求出錯時的處理邏輯
app.listen(3000,()=>{
console.log('starting at port 3000');
});
3.3.2 koa-router獲取URI動態(tài)傳值:
//請求方式http://域名/product/123
router.get('/product/:aid',async (ctx)=>{
console.log(ctx.params); //{ aid: '123' } //獲取動態(tài)路由的數(shù)據(jù)
ctx.body='這是商品頁面';
});