Heim > Artikel > Web-Frontend > Was ist Koa in NodeJS?
koa bezieht sich auf ein auf Node basierendes Web-Framework ähnlich wie Express und hat sich zum Ziel gesetzt, ein kleinerer, ausdrucksstärkerer und robusterer Eckpfeiler im Bereich der Webanwendungs- und API-Entwicklung zu werden. Koa bündelt keine Middleware, sondern bietet eine Reihe eleganter Methoden, mit denen Benutzer schnell und problemlos serverseitige Anwendungen schreiben können.
Die Betriebsumgebung dieses Tutorials: Windows7-System, NodeJS-Version 12.19.0&&koa2.0, Dell G3-Computer.
Koa
ist ein Webentwicklungsframework, das Express ähnelt. Der Gründer ist ebenfalls dieselbe Person. Sein Hauptmerkmal besteht darin, dass es die <code>ES6-Generatorfunktion
verwendet und die Architektur neu gestaltet. Mit anderen Worten: Das Prinzip und die interne Struktur von Koa sind denen von Express sehr ähnlich, die Syntax und die interne Struktur wurden jedoch verbessert. Koa
是一个类似于Express的Web
开发框架,创始人也是同一个人。它的主要特点是,使用了ES6的Generator函数
,进行了架构的重新设计。也就是说,Koa的原理和内部结构很像Express,但是语法和内部结构进行了升级。
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
官方faq
有这样一个问题:”为什么koa不是Express 4.0?“,回答是这样的:”Koa与Express有很大差异,整个设计都是不同的,所以如果将Express 3.0按照这种写法升级到4.0,就意味着重写整个程序。所以,我们觉得创造一个新的库,是更合适的做法。“
一个Koa应用
就是一个对象
,包含了一个middleware
数组,这个数组由一组Generator函数
组成。这些函数负责对HTTP请求进行各种加工,比如生成缓存、指定代理、请求重定向等等。
var koa = require('koa'); var app = koa(); app.use(function *(){ this.body = 'Hello World'; }); app.listen(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);
Koa
的中间件很像Express的中间件
,也是对HTTP请求进行处理的函数
,但是必须是一个Generator函数
。
而且,Koa的中间件是一个级联式(Cascading)
的结构,也就是说,属于是层层调用,第一个中间件调用第二个中间件
,第二个调用第三个
,以此类推。上游的中间件必须等到下游的中间件返回结果
,才会继续执行,这点很像递归。
中间件通过当前应用的use
方法注册。
app.use(function* (next){ var start = new Date; // (1) yield next; // (2) var ms = new Date - start; // (3) console.log('%s %s - %s', this.method, this.url, ms); // (4) });
上面代码中,app.use
方法的参数就是中间件,它是一个Generator函数
, 最大的特征就是function命令
与参数之间,必须有一个星号
。Generator函数的参数next
,表示下一个中间件。Generator
函数内部使用yield
命令,将程序的执行权转交给下一个中间件,即yield next
,要等到下一个中间件返回结果,才会继续往下执行。
Generator函数体内部
,第一行赋值语句首先执行,开始计时,yield
语句将执行权交给下一个中间件,当前中间件就暂停执行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
语句,后面的中间件都不会执行,这一点要引起注意。
app.use(function *(next){ console.log('>> one'); yield next; console.log('<< one'); }); app.use(function *(next){ console.log('>> two'); this.body = 'two'; console.log('<< two'); }); app.use(function *(next){ console.log('>> three'); yield next; console.log('<< three'); });
上面代码中,因为第二个中间件少了yield next
语句,第三个中间件并不会执行。
如果想跳过一个中间件,可以直接在该中间件的第一行语句写上return yield next。
app.use(function* (next) { if (skip) return yield next; })
由于Koa要求中间件唯一的参数就是next
,导致如果要传入其他参数,必须另外写一个返回Generator函数
Koa ist ein neues Web-Framework, das von denselben Leuten wie Express entwickelt wurde und sich zum Ziel gesetzt hat, ein kleinerer, ausdrucksstärkerer und robusterer Eckpfeiler der Webanwendungs- und API-Entwicklung zu werden. Durch die Nutzung asynchroner Funktionen hilft Ihnen Koa dabei, Callback-Funktionen zu verwerfen und die Fehlerbehandlung erheblich zu verbessern. Koa bündelt keine Middleware, bietet jedoch eine Reihe eleganter Methoden, mit denen Sie schnell und reibungslos serverseitige Anwendungen schreiben können.
In der offiziellen FAQ
steht folgende Frage: „Warum ist Koa nicht Express 4.0?“, die Antwort lautet: „Koa unterscheidet sich stark von Express und das gesamte Design ist anders. Wenn Sie also Express 3.0 auf 4.0 aktualisieren, müssen Sie das gesamte Programm neu schreiben. Daher halten wir es für angemessener, eine neue Bibliothek zu erstellen >
Koa-Anwendung
ist ein Objekt
, das ein Array von Middleware
enthält, das aus einer Reihe von Generatorfunktionen besteht Code> >Zusammensetzung. Diese Funktionen sind für verschiedene Verarbeitungen von HTTP-Anfragen verantwortlich, z. B. für die Cache-Erzeugung, die Angabe eines Proxys, die Anforderungsumleitung usw. 🎜<pre class="brush:php;toolbar:false;">function logger(format) {
return function *(next){
var str = format
.replace(&#39;:method&#39;, this.method)
.replace(&#39;:url&#39;, this.url);
console.log(str);
yield next;
}
}
app.use(logger(&#39;:method :url&#39;));</pre><ul>
<li>Im obigen Code ist die Variablen-App eine Koa-Anwendung. Es überwacht Port 3000 und gibt eine Webseite mit dem Inhalt <code>Hello World
zurück.
app.use
-Methode wird verwendet, um die Generator-Funktion
zum middleware
-Array hinzuzufügen. listen
gibt den Überwachungsport an und startet die aktuelle Anwendung. function *random(next) { if ('/random' == this.path) { this.body = Math.floor(Math.random()*10); } else { yield next; } }; function *backwards(next) { if ('/backwards' == this.path) { this.body = 'sdrawkcab'; } else { yield next; } } function *pi(next) { if ('/pi' == this.path) { this.body = String(Math.PI); } else { yield next; } } function *all(next) { yield random.call(this, backwards.call(this, pi.call(this, next))); } app.use(all);
Koa
ist der Middleware von Express
sehr ähnlich und ist auch right Eine Funktion zur Verarbeitung von HTTP-Anfragen
, es muss jedoch eine Generatorfunktion
sein. Kaskadierende
-Struktur, das heißt, sie wird Schicht für Schicht aufgerufen Die erste Middleware ruft die zweite Middleware auf Der Zweite ruft den Dritten auf
und so weiter. Die Upstream-Middleware muss warten, bis die Downstream-Middleware das Ergebnis zurückgibt
, bevor sie mit der Ausführung fortfährt, was einer Rekursion sehr ähnlich ist. use
der aktuellen Anwendung registriert. 🎜function compose(middleware){ return function *(next){ if (!next) next = noop(); var i = middleware.length; while (i--) { next = middleware[i].call(this, next); } yield *next; } } function *noop(){}🎜Im obigen Code ist der Parameter der
app.use
-Methode die Middleware, bei der es sich um eine Generatorfunktion
handelt. Die größte Funktion ist der Funktionsbefehl und dem Parameter muss <code> ein Sternchen
🎜 enthalten. Der Parameter der Generatorfunktion next
repräsentiert die nächste Middleware. Generator
verwendet intern den Befehl yield
, um das Ausführungsrecht des Programms an die nächste Middleware, also yield next
, zu übertragen > Sie müssen warten, bis die Ausführung erst dann fortgesetzt wird, wenn die nächste Middleware ein Ergebnis zurückgibt. 🎜Generator-Funktionskörpers
zuerst die erste Zeile der Zuweisungsanweisungen ausgeführt und das Timing beginnt, app.use(function* (next) { if (this.path === '/') { this.body = 'we are at home!'; } }) // 等同于 app.use(function* (next) { if (this.path !== '/') return yield next; this.body = 'we are at home!'; })🎜Im obigen Code ruft die erste Middleware die zweite Middleware saveResults auf und beide schreiben Inhalte in this.body. Schließlich ist die Ausgabe von this.body wie folgt. 🎜
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)🎜Solange einer Middleware die
yield next
-Anweisung fehlt, wird die nachfolgende Middleware nicht ausgeführt. Dies sollte beachtet werden. 🎜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);🎜Da im obigen Code der zweiten Middleware die Anweisung
yield next
fehlt, wird die dritte Middleware nicht ausgeführt. router.get('/', function *(next) { this.body = 'Hello World!'; });🎜Da
Koa erfordert, dass der einzige Parameter der Middleware next ist
, müssen Sie, wenn Sie andere Parameter übergeben möchten, eine andere Funktion schreiben, die Generatorfunktion
zurückgibt . 🎜🎜router.get('user', '/users/:id', function *(next) { // ... });🎜Im obigen Code ist die eigentliche Middleware der Rückgabewert der Logger-Funktion, und die Logger-Funktion kann Parameter akzeptieren. 🎜
由于中间件的参数统一为next
(意为下一个中间件),因此可以使用.call(this, next)
,将多个中间件进行合并。
function *random(next) { if ('/random' == this.path) { this.body = Math.floor(Math.random()*10); } else { yield next; } }; function *backwards(next) { if ('/backwards' == this.path) { this.body = 'sdrawkcab'; } else { yield next; } } function *pi(next) { if ('/pi' == this.path) { this.body = String(Math.PI); } else { yield next; } } function *all(next) { yield random.call(this, backwards.call(this, pi.call(this, next))); } app.use(all);
上面代码中,中间件all内部,就是依次调用random、backwards、pi,后一个中间件就是前一个中间件的参数。
Koa内部使用koa-compose
模块,进行同样的操作,下面是它的源码。
function compose(middleware){ return function *(next){ if (!next) next = noop(); var i = middleware.length; while (i--) { next = middleware[i].call(this, next); } yield *next; } } function *noop(){}
上面代码中,middleware是中间件数组。前一个中间件的参数是后一个中间件,依次类推。如果最后一个中间件没有next参数,则传入一个空函数。
可以通过this.path属性,判断用户请求的路径,从而起到路由作用。
app.use(function* (next) { if (this.path === '/') { this.body = 'we are at home!'; } }) // 等同于 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('/', 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方法的第一个参数是请求来源,第二个参数是目的地,两者都可以用路径模式的别名代替。
this
表示上下文对象context
,代表一次HTTP请求和回应
,即一次访问/回应的所有信息,都可以从上下文对象获得。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对象的全局属性。
this.state.user = yield User.find(id);
上面代码中,user
属性存放在this.state
对象上面,可以被另一个中间件读取。
context对象的全局方法。
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;
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'); })
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。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');
【推荐学习:《nodejs 教程》】
Das obige ist der detaillierte Inhalt vonWas ist Koa in NodeJS?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!