安装创建项目:

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. iOS 动态修改导航栏颜色 UINavigationBar

    示例 所谓动态修改  意思是 在当前页面滚动的过程中 亦或 是在 触发返回事件\进入一个新的页面  导航栏的动态变化 由于系统级别的navBar 高度集成  很多自己想实现的功能 很不好弄 如果是通过 ...

  2. 【leetcode刷题笔记】Best Time to Buy and Sell Stock II

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  3. Python 3 并发编程多进程之进程与线程

    Python 3 进程与线程 进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的 ...

  4. Python 3 常用模块之 一

    Python 3 模块 一. time模块  时间模块 在Python中,通常有这几种方式来表示时间: 1.1 时间戳(timestamp): 通常来说,时间戳表示的是从1970年1月1日00:00: ...

  5. BestCoder Round #4 之 Miaomiao's Geometry(2014/8/10)

    最后收到邮件说注意小数的问题!此代码并没有过所有数据,请读者参考算法, 自己再去修改一下吧!注意小数问题! Miaomiao's Geometry Time Limit: 2000/1000 MS ( ...

  6. LINQ 学习路程 -- 查询操作 Aggregate

    聚合操作执行数学的运算,如平均数.合计.总数.最大值.最小值 Method Description Aggregate 在集合上执行自定义聚集操作 Average 求平均数 Count 求集合的总数 ...

  7. 启动Hadoop时DFSZKFailoverController没有启动

    在启动Hadoop成功后,并没有报错信息,jps查看进程,发现DFSZKFailoverController没有启动成功,后来发现是因为防火墙的原因,关掉重试就OK了 systemctl stop f ...

  8. HTML5坦克大战

    在JavaScript中,不要在变量为定义之前去使用,这样很难察觉并且无法运行. 颜色不对. 当我的坦克移动时,敌人坦克消失. tankGame3.html <!DOCTYPE html> ...

  9. httpRequest.CookieContainer= cookie 与 httpRequest.Headers.Add("Cookie", cookie)

    这两天做了一个获取cookie并且携带此cookie去请求另外一个url地址,中间携带cookie用了两种方式:1. httpRequest.CookieContainer= cookie (此coo ...

  10. 十二 Django框架,自定义分页

    自定义分页模块 #!/usr/bin/env python #coding:utf-8 from django.utils.safestring import mark_safe #封装分页类模块 c ...