这一章步骤太多了,还是需要去调看廖雪峰老师的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>