這一章步驟太多了,還是需要去調看廖雪峰老師的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>
