安装创建项目:

1.一定要全局安装(koa1.2和koa2都己经支持)

npm install koa-generator -g 

2.
koa1 生成一个test项目,切到test目录并下载依赖

koa1创建项目

koa test
cd test
npm install
运行:npm start
访问:http://localhost:3000

Koa是一个类似于Express的Web开发框架,创始人也是同一个人。它的主要特点是,使用了ES6的Generator函数,进行了架构的重新设计。也就是说,Koa的原理和内部结构很像Express,但是语法和内部结构进行了升级。

官方faq有这样一个问题:”为什么koa不是Express 4.0?“,回答是这样的:”Koa与Express有很大差异,整个设计都是不同的,所以如果将Express 3.0按照这种写法升级到4.0,就意味着重写整个程序。所以,我们觉得创造一个新的库,是更合适的做法。“

Koa应用

一个Koa应用就是一个对象,包含了一个middleware数组,这个数组由一组Generator函数组成。这些函数负责对HTTP请求进行各种加工,比如生成缓存、指定代理、请求重定向等等。

 var koa = require('koa');
var app = koa(); app.use(function *(){
this.body = 'Hello World';
}); app.listen(3000);
要安装koa才能测试

上面代码中,变量app就是一个Koa应用。它监听3000端口,返回一个内容为Hello World的网页。

app.use方法用于向middleware数组添加Generator函数。

listen方法指定监听端口,并启动当前应用。它实际上等同于下面的代码

 var http = require('http');
var koa = require('koa');
var app = koa();
http.createServer(app.callback()).listen(3000);

中间件

下面是一个两个中间件级联的例子

 app.use(function *() {
this.body = "header\n";
yield saveResults.call(this);
this.body += "footer\n";
}); function *saveResults() {
this.body += "Results Saved!\n";
}

上面代码中,第一个中间件调用第二个中间件saveResults,它们都向this.body写入内容。最后,this.body的输出如下。

header Results Saved! footer

只要有一个中间件缺少yield next语句,后面的中间件都不会执行,这一点要引起注意。

如果想跳过一个中间件,可以直接在该中间件的第一行语句写上return yield next

 app.use(function* (next) {
if (skip) return yield next;
})

路由

可以通过this.path属性,判断用户请求的路径,从而起到路由作用。

 app.use(function* (next) {
if (this.path === '/') {
this.body = 'we are at home!';
} else {
yield next;
}
}) // 等同于 app.use(function* (next) {
if (this.path !== '/') return yield next;
this.body = 'we are at home!';
})

下面是多路径的例子。

 let koa = require('koa')

 let app = koa()

 // normal route
app.use(function* (next) {
if (this.path !== '/') {
return yield next
} this.body = 'hello world'
}); // /404 route
app.use(function* (next) {
if (this.path !== '/404') {
return yield next;
} this.body = 'page not found'
}); // /500 route
app.use(function* (next) {
if (this.path !== '/500') {
return yield next;
} this.body = 'internal server error'
}); app.listen(8080)

上面代码中,每一个中间件负责一个路径,如果路径不符合,就传递给下一个中间件。

复杂的路由需要安装koa-router插件。

 var app = require('koa')();
var Router = require('koa-router'); var myRouter = new Router(); myRouter.get('/', function *(next) {
this.response.body = 'Hello World!';
}); app.use(myRouter.routes()); app.listen(3000);

上面代码对根路径设置路由。

Koa-router实例提供一系列动词方法,即一种HTTP动词对应一种方法。典型的动词方法有以下五种。

  • router.get()
  • router.post()
  • router.put()
  • router.del()
  • router.patch()

这些动词方法可以接受两个参数,第一个是路径模式,第二个是对应的控制器方法(中间件),定义用户请求该路径时服务器行为。

 router.get('/', function *(next) {
this.body = 'Hello World!';
});

上面代码中,router.get方法的第一个参数是根路径,第二个参数是对应的函数方法。

注意,路径匹配的时候,不会把查询字符串考虑在内。比如,/index?param=xyz匹配路径/index

有些路径模式比较复杂,Koa-router允许为路径模式起别名。起名时,别名要添加为动词方法的第一个参数,这时动词方法变成接受三个参数。

 router.get('user', '/users/:id', function *(next) {
// ...
});
上面代码中,路径模式\users\:id的名字就是user。路径的名称,可以用来引用对应的具体路径,比如url方法可以根据路径名称,
结合给定的参数,生成具体的路径。
Koa-router允许为路径统一添加前缀。
 var router = new Router({
prefix: '/users'
}); router.get('/', ...); // 等同于"/users"
router.get('/:id', ...); // 等同于"/users/:id"

路径的参数通过this.params属性获取,该属性返回一个对象,所有路径参数都是该对象的成员。

// 访问 /programming/how-to-node
router.get('/:category/:title', function *(next) {
console.log(this.params);
// => { category: 'programming', title: 'how-to-node' }
});

param方法可以针对命名参数,设置验证条件。

 router
.get('/users/:user', function *(next) {
this.body = this.user;
})
.param('user', function *(id, next) {
var users = [ '0号用户', '1号用户', '2号用户'];
this.user = users[id];
if (!this.user) return this.status = 404;
yield next;
})

上面代码中,如果/users/:user的参数user对应的不是有效用户(比如访问/users/3),param方法注册的中间件会查到,就会返回404错误。

redirect方法会将某个路径的请求,重定向到另一个路径,并返回301状态码。

 router.redirect('/login', 'sign-in');

 // 等同于
router.all('/login', function *() {
this.redirect('/sign-in');
this.status = 301;
});

redirect方法的第一个参数是请求来源,第二个参数是目的地,两者都可以用路径模式的别名代替。

错误处理机制

 app.use(function *() {
try {
yield saveResults();
} catch (err) {
this.throw(400, '数据无效');
}
});

上面代码自行部署了try…catch代码块,一旦产生错误,就用this.throw方法抛出。该方法可以将指定的状态码和错误信息,返回给客户端。

对于未捕获错误,可以设置error事件的监听函数。

 app.on('error', function(err){
log.error('server error', err);
});

this.throw方法用于向客户端抛出一个错误。

 this.throw(403);
this.throw('name required', 400);
this.throw(400, 'name required');
this.throw('something exploded'); this.throw('name required', 400)
// 等同于
var err = new Error('name required');
err.status = 400;
throw err;

this.throw方法的两个参数,一个是错误码,另一个是报错信息。如果省略状态码,默认是500错误。

this.assert方法用于在中间件之中断言,用法类似于Node的assert模块

 this.assert(this.user, 401, 'User not found. Please login!');

上面代码中,如果this.user属性不存在,会抛出一个401错误。

cookie

cookie的读取和设置。

 this.cookies.get('view');
this.cookies.set('view', n);

get和set方法都可以接受第三个参数,表示配置参数。其中的signed参数,用于指定cookie是否加密。如果指定加密的话,必须用app.keys指定加密短语。

 app.keys = ['secret1', 'secret2'];
this.cookies.set('name', '张三', { signed: true });

this.cookie的配置对象的属性如下。

  • signed:cookie是否加密。
  • expires:cookie何时过期
  • path:cookie的路径,默认是“/”。
  • domain:cookie的域名。
  • secure:cookie是否只有https请求下才发送。
  • httpOnly:是否只有服务器可以取到cookie,默认为true。

session

 var session = require('koa-session');
var koa = require('koa');
var app = koa(); app.keys = ['some secret hurr'];
app.use(session(app)); app.use(function *(){
var n = this.session.views || 0;
this.session.views = ++n;
this.body = n + ' views';
}) app.listen(3000);
console.log('listening on port 3000');
 可以把session存到mysql中
安装npm install koa-generic-session --save-dev
2.app.js中
var session = require('koa-generic-session'); app.keys = ['my secret key']; // needed for cookie-signing,设置一个签名 Cookie 的密钥
app.use(session()); 3.
this.session.loginbean 方法二:
session映射到mysql
1.加安装
npm install mysql --save-dev
npm install koa-mysql-session --save-dev app.js中:
var session = require('koa-generic-session');
const mysql = require('mysql');
const MysqlStore = require('koa-mysql-session'); app.keys = ['my secret key']; // needed for cookie-signing,设置一个签名 Cookie 的密钥
app.use(session({store:new MysqlStore({
host: 'localhost', //主机
user: 'root', //MySQL认证用户名
password: 'root', //MySQL认证用户密码
database: 'kameng',
port: '3306', //端口号
acquireTimeout:0
})}));

Request对象

Request对象表示HTTP请求。

(1)this.request.header

返回一个对象,包含所有HTTP请求的头信息。它也可以写成this.request.headers

(2)this.request.method

返回HTTP请求的方法,该属性可读写。

(3)this.request.length

返回HTTP请求的Content-Length属性,取不到值,则返回undefined。

(4)this.request.path

返回HTTP请求的路径,该属性可读写。

(5)this.request.href

返回HTTP请求的完整路径,包括协议、端口和url。

 this.request.href
// http://example.com/foo/bar?q=1

(6)this.request.querystring

返回HTTP请求的查询字符串,不含问号。该属性可读写。

(7)this.request.search

返回HTTP请求的查询字符串,含问号。该属性可读写。

(8)this.request.host

返回HTTP请求的主机(含端口号)。

(9)this.request.hostname

返回HTTP的主机名(不含端口号)。

(10)this.request.type

返回HTTP请求的Content-Type属性

 var ct = this.request.type;
// "image/png"

(11)this.request.charset

返回HTTP请求的字符集。

 this.request.charset
// "utf-8

路由

可以通过this.path属性,判断用户请求的路径,从而起到路由作用。

app.use(function* (next) {
if (this.path === '/') {
this.body = 'we are at home!';
} else {
yield next;
}
}) // 等同于 app.use(function* (next) {
if (this.path !== '/') return yield next;
this.body = 'we are at home!';
})

下面是多路径的例子。

let koa = require('koa')

let app = koa()

// normal route
app.use(function* (next) {
if (this.path !== '/') {
return yield next
} this.body = 'hello world'
}); // /404 route
app.use(function* (next) {
if (this.path !== '/404') {
return yield next;
} this.body = 'page not found'
}); // /500 route
app.use(function* (next) {
if (this.path !== '/500') {
return yield next;
} this.body = 'internal server error'
}); app.listen(8080)

上面代码中,每一个中间件负责一个路径,如果路径不符合,就传递给下一个中间件。

复杂的路由需要安装koa-router插件。

var app = require('koa')();
var Router = require('koa-router'); var myRouter = new Router(); myRouter.get('/', function *(next) {
this.response.body = 'Hello World!';
}); app.use(myRouter.routes()); app.listen(3000);

上面代码对根路径设置路由。

Koa-router实例提供一系列动词方法,即一种HTTP动词对应一种方法。典型的动词方法有以下五种。

  • router.get()
  • router.post()
  • router.put()
  • router.del()
  • router.patch()

这些动词方法可以接受两个参数,第一个是路径模式,第二个是对应的控制器方法(中间件),定义用户请求该路径时服务器行为。

router.get('/', function *(next) {
this.body = 'Hello World!';
});

上面代码中,router.get方法的第一个参数是根路径,第二个参数是对应的函数方法。

注意,路径匹配的时候,不会把查询字符串考虑在内。比如,/index?param=xyz匹配路径/index

有些路径模式比较复杂,Koa-router允许为路径模式起别名。起名时,别名要添加为动词方法的第一个参数,这时动词方法变成接受三个参数。

router.get('user', '/users/:id', function *(next) {
// ...
});

上面代码中,路径模式\users\:id的名字就是user。路径的名称,可以用来引用对应的具体路径,比如url方法可以根据路径名称,结合给定的参数,生成具体的路径。

router.url('user', 3);
// => "/users/3" router.url('user', { id: 3 });
// => "/users/3"

上面代码中,user就是路径模式的名称,对应具体路径/users/:id。url方法的第二个参数3,表示给定id的值是3,因此最后生成的路径是/users/3

Koa-router允许为路径统一添加前缀。

var router = new Router({
prefix: '/users'
}); router.get('/', ...); // 等同于"/users"
router.get('/:id', ...); // 等同于"/users/:id"

路径的参数通过this.params属性获取,该属性返回一个对象,所有路径参数都是该对象的成员。

// 访问 /programming/how-to-node
router.get('/:category/:title', function *(next) {
console.log(this.params);
// => { category: 'programming', title: 'how-to-node' }
});

param方法可以针对命名参数,设置验证条件。

router
.get('/users/:user', function *(next) {
this.body = this.user;
})
.param('user', function *(id, next) {
var users = [ '0号用户', '1号用户', '2号用户'];
this.user = users[id];
if (!this.user) return this.status = 404;
yield next;
})

上面代码中,如果/users/:user的参数user对应的不是有效用户(比如访问/users/3),param方法注册的中间件会查到,就会返回404错误。

redirect方法会将某个路径的请求,重定向到另一个路径,并返回301状态码。

router.redirect('/login', 'sign-in');

// 等同于
router.all('/login', function *() {
this.redirect('/sign-in');
this.status = 301;
});

redirect方法的第一个参数是请求来源,第二个参数是目的地,两者都可以用路径模式的别名代替。

context对象

中间件当中的this表示上下文对象context,代表一次HTTP请求和回应,即一次访问/回应的所有信息,都可以从上下文对象获得。context对象封装了request和response对象,并且提供了一些辅助方法。每次HTTP请求,就会创建一个新的context对象。

app.use(function *(){
this; // is the Context
this.request; // is a koa Request
this.response; // is a koa Response
});

context对象的很多方法,其实是定义在ctx.request对象或ctx.response对象上面,比如,ctx.type和ctx.length对应于ctx.response.type和ctx.response.length,ctx.path和ctx.method对应于ctx.request.path和ctx.request.method。

context对象的全局属性。

  • request:指向Request对象
  • response:指向Response对象
  • req:指向Node的request对象
  • res:指向Node的response对象
  • app:指向App对象
  • state:用于在中间件传递信息。
this.state.user = yield User.find(id);

上面代码中,user属性存放在this.state对象上面,可以被另一个中间件读取。

context对象的全局方法。

  • throw():抛出错误,直接决定了HTTP回应的状态码。
  • assert():如果一个表达式为false,则抛出一个错误。
this.throw(403);
this.throw('name required', 400);
this.throw('something exploded'); this.throw(400, 'name required');
// 等同于
var err = new Error('name required');
err.status = 400;
throw err;

assert方法的例子。

// 格式
ctx.assert(value, [msg], [status], [properties]) // 例子
this.assert(this.user, 401, 'User not found. Please login!');

以下模块解析POST请求的数据。

  • co-body
  • https://github.com/koajs/body-parser
  • https://github.com/koajs/body-parsers
var parse = require('co-body');

// in Koa handler
var body = yield parse(this);

错误处理机制

Koa提供内置的错误处理机制,任何中间件抛出的错误都会被捕捉到,引发向客户端返回一个500错误,而不会导致进程停止,因此也就不需要forever这样的模块重启进程。

app.use(function *() {
throw new Error();
});

上面代码中,中间件内部抛出一个错误,并不会导致Koa应用挂掉。Koa内置的错误处理机制,会捕捉到这个错误。

当然,也可以额外部署自己的错误处理机制。

app.use(function *() {
try {
yield saveResults();
} catch (err) {
this.throw(400, '数据无效');
}
});

上面代码自行部署了try…catch代码块,一旦产生错误,就用this.throw方法抛出。该方法可以将指定的状态码和错误信息,返回给客户端。

对于未捕获错误,可以设置error事件的监听函数。

app.on('error', function(err){
log.error('server error', err);
});

error事件的监听函数还可以接受上下文对象,作为第二个参数。

app.on('error', function(err, ctx){
log.error('server error', err, ctx);
});

如果一个错误没有被捕获,koa会向客户端返回一个500错误“Internal Server Error”。

this.throw方法用于向客户端抛出一个错误。

this.throw(403);
this.throw('name required', 400);
this.throw(400, 'name required');
this.throw('something exploded'); this.throw('name required', 400)
// 等同于
var err = new Error('name required');
err.status = 400;
throw err;

this.throw方法的两个参数,一个是错误码,另一个是报错信息。如果省略状态码,默认是500错误。

this.assert方法用于在中间件之中断言,用法类似于Node的assert模块。

this.assert(this.user, 401, 'User not found. Please login!');

上面代码中,如果this.user属性不存在,会抛出一个401错误。

由于中间件是层级式调用,所以可以把try { yield next }当成第一个中间件。

app.use(function *(next) {
try {
yield next;
} catch (err) {
this.status = err.status || 500;
this.body = err.message;
this.app.emit('error', err, this);
}
}); app.use(function *(next) {
throw new Error('some error');
})

CSRF攻击

CSRF攻击是指用户的session被劫持,用来冒充用户的攻击。

koa-csrf插件用来防止CSRF攻击。原理是在session之中写入一个秘密的token,用户每次使用POST方法提交数据的时候,必须含有这个token,否则就会抛出错误。

 var koa = require('koa');
var session = require('koa-session');
var csrf = require('koa-csrf');
var route = require('koa-route'); var app = module.exports = koa(); app.keys = ['session key', 'csrf example'];
app.use(session(app)); app.use(csrf()); app.use(route.get('/token', token));
app.use(route.post('/post', post)); function* token () {
this.body = this.csrf;
} function* post() {
this.body = {ok: true};
} app.listen(3000);

POST请求含有token,可以是以下几种方式之一,koa-csrf插件就能获得token。

  • 表单的_csrf字段
  • 查询字符串的_csrf字段
  • HTTP请求头信息的x-csrf-token字段
  • HTTP请求头信息的x-xsrf-token字段
 

Koa1 框架的更多相关文章

  1. koa2,koa1框架安装

    koa2版本安装: npm install koa@ -g hello2.js var Koa = require('koa'); var app = new Koa(); app.use(ctx = ...

  2. FKP,一套全栈框架,基于react、webpack、koa1、babel

    FKP-REST是一套前后端分离,基于javascript的全栈实现,基于node的高性能,易部署性及javascript前后端语言的一致性,学习成本,时间成本及项目快速启动等等方面,FKP都是一种不 ...

  3. Vue应用框架整合与实战--Vue技术生态圈篇

    实用框架以及工具 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 Element-UI ★13489 - 饿了么出品的Vue2的web UI工具套件 Vux ★8133 ...

  4. Koa 框架教程

    Koa 框架教程   作者: 阮一峰 日期: 2017年8月 9日 Node 主要用在开发 Web 应用.这决定了使用 Node,往往离不开 Web 应用框架. Koa 就是一种简单好用的 Web 框 ...

  5. Koa 框架整理

    学习交流 Koa使用了ES6规范的generator和异步编程是一个更轻量级Web开发的框架,Koa 的先天优势在于 generator.由于是我个人的分享交流,所以Node基础.ES6标准.Web开 ...

  6. vue 专题 vue2.0各大前端移动端ui框架组件展示

    Vue 专题 一个数据驱动的组件,为现代化的 Web 界面而生.具有可扩展的数据绑定机制,原生对象即模型,简洁明了的 API 组件化 UI 构建 多个轻量库搭配使用 请访问链接: https://ww ...

  7. VUE常用UI组件插件及框架

    UI组件及框架 element - 饿了么出品的Vue2的web UI工具套件 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开源 UI 组件库 Keen-UI - ...

  8. vue统计组件库和ui框架

    UI组件 element ★13489 - 饿了么出品的Vue2的web UI工具套件 Vux ★8133 - 基于Vue和WeUI的组件库 iview ★6634 - 基于 Vuejs 的开源 UI ...

  9. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

随机推荐

  1. elk示例-精简版2

    作者:Danbo 时间:2016-03-13 1.保存进Elasticsearch Logstash可以试用不同的协议实现完成将数据写入Elasticsearch的工作,本节中介绍HTTP方式. 配置 ...

  2. 【leetcode刷题笔记】Max Points on a Line

    Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. ...

  3. ICP 求解相机思路

    1.之前仍然是需要创建find_feature_matches,和pixel2cam,一个是用来匹配描述子的,一个是把像素坐标转成归一化平面坐标的.里面的变量都要带上&.2.因为是3d-3d. ...

  4. Spark- Transformation实战

    RDD的算子分为两类,是 Trans formation(Lazy),一类是 Action(触发任务执行RDD不存在真正要计算的数据,而是记录了RDD的转换关系(调用了什么方法,传入什么函数) RDD ...

  5. Codeforces 479E Riding in a Lift:前缀和/差分优化dp

    题目链接:http://codeforces.com/problemset/problem/479/E 题意: 有一栋n层的房子. 还有一个无聊的人在玩电梯,每次玩电梯都会从某一层坐到另外一层. 他初 ...

  6. 四 Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置

    Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...

  7. hdu 2018 母牛的故事(简单dp)

    母牛的故事 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  8. strnpy函数

    函数原型: char * strncpy ( char * destination, const char * source, size_t num ); 功能:从字符串source中复制 num个字 ...

  9. 自定义ajax小工具以及使用

    function createXMLHttpRequest(){ try{ return new XMLHttpRequest(); }catch(e){ try{ return new Active ...

  10. zepto不支持animate({scrollTop:"100px"})的解决办法

    在移动web项目的开发中,遇到一个通过点击页面自动到相应的楼层处的需求,最初的想法就是使用html的target属性进行切换,但实际效果十分死板,显得毫无交互性.该前端架构采用zepto这个轻库进行开 ...