這一章步驟太多了,還是需要去調看廖雪峰老師的JavaScript教程
1.創建koa2工程:app.js
// 導入koa,和koa 1.x不同,在koa2中,我們導入的是一個class,因此用大寫的Koa表示: const Koa = require('koa'); // 創建一個Koa對象表示web app本身: const app = new Koa(); // 對於任何請求,app將調用該異步函數處理請求: app.use(async (ctx, next) => { //參數ctx是由koa傳入的封裝了request和response的變量,我們可以通過它訪問request和response,next是koa傳入的將要處理的下一個異步函數 await next(); ctx.response.type = 'text/html'; ctx.response.body = '<h1>Hello, koa2!</h1>'; }); // 在端口3000監聽: app.listen(3000); console.log('app started at port 3000...');
由async
標記的函數稱為異步函數,在異步函數中,可以用await
調用另一個異步函數,這兩個關鍵字將在ES7中引入。
封裝:
方法一:可以用npm命令直接安裝koa。先打開命令提示符,務必把當前目錄切換到hello-koa
這個目錄,然后執行命令:
C:\...\hello-koa> npm install koa@2.0.0
方法二:在hello-koa
這個目錄下創建一個package.json
,這個文件描述了我們的hello-koa
工程會用到哪些包。完整的文件內容如下:
{ "name": "hello-koa2", "version": "1.0.0", "description": "Hello Koa 2 example with async", "main": "start.js", "scripts": { "start": "node start.js" }, "keywords": [ "koa", "async" ], "author": "Michael Liao", "license": "Apache-2.0", "repository": { "type": "git", "url": "https://github.com/michaelliao/learn-javascript.git" }, "dependencies": { "babel-core": "6.13.2", "babel-polyfill": "6.13.0", "babel-preset-es2015-node6": "0.3.0", "babel-preset-stage-3": "6.5.0", "koa": "2.0.0" } }
然后,我們在hello-koa
目錄下執行npm install
就可以把所需包以及依賴包一次性全部裝好:
C:\...\hello-koa> npm install
因為是ES7,所以要先轉化代碼,再執行:start.js
var register = require('babel-core/register'); register({ presets: ['stage-3'] }); require('./app.js');
2.koa把很多async函數組成一個處理鏈,每個async函數都可以做一些自己的事情,然后用await next()
來調用下一個async函數。我們把每個async函數稱為middleware
下面用3個middleware組成處理鏈,依次打印日志,記錄處理時間,輸出HTML:
app.use(async (ctx, next) => { console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL await next(); // 調用下一個middleware }); app.use(async (ctx, next) => { const start = new Date().getTime(); // 當前時間 await next(); // 調用下一個middleware const ms = new Date().getTime() - start; // 耗費時間 console.log(`Time: ${ms}ms`); // 打印耗費時間 }); app.use(async (ctx, next) => { await next(); ctx.response.type = 'text/html'; ctx.response.body = '<h1>Hello, koa2!</h1>'; });
如果一個middleware沒有調用await next()
,后續的middleware將不再執行了。
3.一個檢測用戶權限的middleware可以決定是否繼續處理請求,還是直接返回403錯誤:
app.use(async (ctx, next) => { if (await checkUserPermission(ctx)) { await next(); } else { ctx.response.status = 403; } });
ctx
對象有一些簡寫的方法,例如ctx.url
相當於ctx.request.url
,ctx.type
相當於ctx.response.type
。
4.在localhost下處理不同的url用koa-router:
const Koa = require('koa'); // 注意require('koa-router')返回的是函數: const router = require('koa-router')(); //最后的()就是函數調用 const app = new Koa(); // log request URL: app.use(async (ctx, next) => { console.log(`Process ${ctx.request.method} ${ctx.request.url}...`); await next(); }); // add url-route,注冊GET請求: router.get('/hello/:name', async (ctx, next) => { var name = ctx.params.name; ctx.response.body = `<h1>Hello, ${name}!</h1>`; //在http://localhost:3000/hello/koa里顯示hello,koa! }); router.get('/', async (ctx, next) => { ctx.response.body = '<h1>Index</h1>'; //在http://localhost:3000里顯示Index }); // add router middleware: app.use(router.routes()); app.listen(3000); console.log('app started at port 3000...');
5.處理post請求用koa-bodyparser
,寫一個簡單的登錄表單:
router.get('/', async (ctx, next) => { ctx.response.body = `<h1>Index</h1> <form action="/signin" method="post"> <p>Name: <input name="name" value="koa"></p> <p>Password: <input name="password" type="password"></p> <p><input type="submit" value="Submit"></p> </form>`; }); router.post('/signin', async (ctx, next) => { var name = ctx.request.body.name || '', //默認name字段為空 password = ctx.request.body.password || ''; console.log(`signin with name: ${name}, password: ${password}`); if (name === 'koa' && password === '12345') { ctx.response.body = `<h1>Welcome, ${name}!</h1>`; } else { ctx.response.body = `<h1>Login failed!</h1> <p><a href="/">Try again</a></p>`; } });
6.Nunjucks是一個模板引擎。
先定義一個基本的網頁框架base.html
:
<html><body> {% block header %} <h3>Unnamed</h3> {% endblock %} {% block body %} <div>No body</div> {% endblock %} {% block footer %} <div>copyright</div> {% endblock %} </body>
base.html
定義了三個可編輯的塊,分別命名為header
、body
和footer
。子模板可以有選擇地對塊進行重新定義:
{% extends 'base.html' %} {% block header %}<h1>{{ header }}</h1>{% endblock %} {% block body %}<p>{{ body }}</p>{% endblock %}
然后,我們對子模板進行渲染:
console.log(env.render('extend.html', { header: 'Hello', body: 'bla bla bla...' }));
輸出HTML如下:
<html><body> <h1>Hello</h1> <p>bla bla bla...</p> <div>copyright</div> <-- footer沒有重定義,所以仍使用父模板的內容 </body>