欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          nodejs中的koa是什么

          koa指的是一個類似于Express的基于Node實現(xiàn)的web框架,致力于成為web應(yīng)用和API開發(fā)領(lǐng)域中的一個更小、更富有表現(xiàn)力、更健壯的基石。Koa并沒有捆綁任何中間件,而是提供了一套優(yōu)雅的方法,幫助用戶快速而愉快地編寫服務(wù)端應(yīng)用程序。

          nodejs中的koa是什么

          本教程操作環(huán)境:windows7系統(tǒng)、nodejs 12.19.0&&koa2.0版、Dell G3電腦。

          Koa是一個類似于Express的Web開發(fā)框架,創(chuàng)始人也是同一個人。它的主要特點是,使用了ES6的Generator函數(shù),進(jìn)行了架構(gòu)的重新設(shè)計。也就是說,Koa的原理和內(nèi)部結(jié)構(gòu)很像Express,但是語法和內(nèi)部結(jié)構(gòu)進(jìn)行了升級。

          Koa 是一個新的 web 框架,由 Express 幕后的原班人馬打造, 致力于成為 web 應(yīng)用和 API 開發(fā)領(lǐng)域中的一個更小、更富有表現(xiàn)力、更健壯的基石。 通過利用 async 函數(shù),Koa 幫你丟棄回調(diào)函數(shù),并有力地增強(qiáng)錯誤處理。 Koa 并沒有捆綁任何中間件, 而是提供了一套優(yōu)雅的方法,幫助您快速而愉快地編寫服務(wù)端應(yīng)用程序。

          官方faq有這樣一個問題:”為什么koa不是Express 4.0?“,回答是這樣的:”Koa與Express有很大差異,整個設(shè)計都是不同的,所以如果將Express 3.0按照這種寫法升級到4.0,就意味著重寫整個程序。所以,我們覺得創(chuàng)造一個新的庫,是更合適的做法。“

          1 Koa應(yīng)用

          一個Koa應(yīng)用就是一個對象,包含了一個middleware數(shù)組,這個數(shù)組由一組Generator函數(shù)組成。這些函數(shù)負(fù)責(zé)對HTTP請求進(jìn)行各種加工,比如生成緩存、指定代理、請求重定向等等。

          var koa = require('koa'); var app = koa();  app.use(function *(){   this.body = 'Hello World'; });  app.listen(3000);
          • 上面代碼中,變量app就是一個Koa應(yīng)用。它監(jiān)聽3000端口,返回一個內(nèi)容為Hello World的網(wǎng)頁。
          • app.use方法用于向middleware數(shù)組添加Generator函數(shù)。
          • listen方法指定監(jiān)聽端口,并啟動當(dāng)前應(yīng)用。
            它實際上等同于下面的代碼。
          var http = require('http'); var koa = require('koa'); var app = koa(); http.createServer(app.callback()).listen(3000);

          2 中間件

          Koa的中間件很像Express的中間件,也是對HTTP請求進(jìn)行處理的函數(shù),但是必須是一個Generator函數(shù)。
          而且,Koa的中間件是一個級聯(lián)式(Cascading)的結(jié)構(gòu),也就是說,屬于是層層調(diào)用,第一個中間件調(diào)用第二個中間件第二個調(diào)用第三個,以此類推。上游的中間件必須等到下游的中間件返回結(jié)果,才會繼續(xù)執(zhí)行,這點很像遞歸。
          中間件通過當(dāng)前應(yīng)用的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方法的參數(shù)就是中間件,它是一個Generator函數(shù), 最大的特征就是function命令與參數(shù)之間,必須有一個星號。Generator函數(shù)的參數(shù)next,表示下一個中間件。
          Generator函數(shù)內(nèi)部使用yield命令,將程序的執(zhí)行權(quán)轉(zhuǎn)交給下一個中間件,即yield next,要等到下一個中間件返回結(jié)果,才會繼續(xù)往下執(zhí)行。

          • 上面代碼中,Generator函數(shù)體內(nèi)部,第一行賦值語句首先執(zhí)行,開始計時,
          • 第二行yield語句將執(zhí)行權(quán)交給下一個中間件,當(dāng)前中間件就暫停執(zhí)行
          • 等到后面的中間件全部執(zhí)行完成,執(zhí)行權(quán)就回到原來暫停的地方,繼續(xù)往下執(zhí)行,這時才會執(zhí)行第三行,
          • 計算這個過程一共花了多少時間,第四行將這個時間打印出來。
            下面是一個兩個中間件級聯(lián)的例子。
          app.use(function *() {   this.body = "headern";   yield saveResults.call(this);   this.body += "footern"; });  function *saveResults() {   this.body += "Results Saved!n"; }

          上面代碼中,第一個中間件調(diào)用第二個中間件saveResults,它們都向this.body寫入內(nèi)容。最后,this.body的輸出如下。

          header Results Saved! footer

          只要有一個中間件缺少yield next語句,后面的中間件都不會執(zhí)行,這一點要引起注意。

          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語句,第三個中間件并不會執(zhí)行。
          如果想跳過一個中間件,可以直接在該中間件的第一行語句寫上return yield next。

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

          由于Koa要求中間件唯一的參數(shù)就是next,導(dǎo)致如果要傳入其他參數(shù),必須另外寫一個返回Generator函數(shù)的函數(shù)。

          function logger(format) {   return function *(next){     var str = format       .replace(':method', this.method)       .replace(':url', this.url);      console.log(str);      yield next;   } } app.use(logger(':method :url'));

          上面代碼中,真正的中間件是logger函數(shù)的返回值,而logger函數(shù)是可以接受參數(shù)的。

          3 多個中間件的合并

          由于中間件的參數(shù)統(tǒng)一為next(意為下一個中間件),因此可以使用.call(this, next),將多個中間件進(jìn)行合并。

          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內(nèi)部,就是依次調(diào)用random、backwards、pi,后一個中間件就是前一個中間件的參數(shù)。
          Koa內(nèi)部使用koa-compose模塊,進(jìn)行同樣的操作,下面是它的源碼。

          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是中間件數(shù)組。前一個中間件的參數(shù)是后一個中間件,依次類推。如果最后一個中間件沒有next參數(shù),則傳入一個空函數(shù)。

          4 路由

          可以通過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)

          上面代碼中,每一個中間件負(fù)責(zé)一個路徑,如果路徑不符合,就傳遞給下一個中間件。
          復(fù)雜的路由需要安裝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);

          上面代碼對根路徑設(shè)置路由。
          Koa-router實例提供一系列動詞方法,即一種HTTP動詞對應(yīng)一種方法。典型的動詞方法有以下五種。

          • router.get()
          • router.post()
          • router.put()
          • router.del()
          • router.patch()
            這些動詞方法可以接受兩個參數(shù),第一個是路徑模式,第二個是對應(yīng)的控制器方法(中間件),定義用戶請求該路徑時服務(wù)器行為。
          router.get('/', function *(next) {   this.body = 'Hello World!'; });

          上面代碼中,router.get方法的第一個參數(shù)是根路徑,第二個參數(shù)是對應(yīng)的函數(shù)方法。
          注意,路徑匹配的時候,不會把查詢字符串考慮在內(nèi)。比如,/index?param=xyz匹配路徑/index。
          有些路徑模式比較復(fù)雜,Koa-router允許為路徑模式起別名。
          起名時,別名要添加為動詞方法的第一個參數(shù),這時動詞方法變成接受三個參數(shù)。

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

          上面代碼中,路徑模式users:id的名字就是user。路徑的名稱,可以用來引用對應(yīng)的具體路徑,比如url方法可以根據(jù)路徑名稱,結(jié)合給定的參數(shù),生成具體的路徑。

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

          上面代碼中,user就是路徑模式的名稱,對應(yīng)具體路徑/users/:id。url方法的第二個參數(shù)3,表示給定id的值是3,因此最后生成的路徑是/users/3。
          Koa-router允許為路徑統(tǒng)一添加前綴。

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

          路徑的參數(shù)通過this.params屬性獲取,該屬性返回一個對象,所有路徑參數(shù)都是該對象的成員。

          // 訪問 /programming/how-to-node router.get('/:category/:title', function *(next) {   console.log(this.params);   // => { category: 'programming', title: 'how-to-node' } }); param方法可以針對命名參數(shù),設(shè)置驗證條件。  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的參數(shù)user對應(yīng)的不是有效用戶(比如訪問/users/3),param方法注冊的中間件會查到,就會返回404錯誤。
          redirect方法會將某個路徑的請求,重定向到另一個路徑,并返回301狀態(tài)碼。

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

          redirect方法的第一個參數(shù)是請求來源,第二個參數(shù)是目的地,兩者都可以用路徑模式的別名代替。

          5 context對象

          • 中間件當(dāng)中的this表示上下文對象context,代表一次HTTP請求和回應(yīng),即一次訪問/回應(yīng)的所有信息,都可以從上下文對象獲得。
          • context對象封裝了request和response對象,并且提供了一些輔助方法。每次HTTP請求,就會創(chuàng)建一個新的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.typectx.length對應(yīng)于ctx.response.typectx.response.length,ctx.path和ctx.method對應(yīng)于ctx.request.path和ctx.request.method。
          context對象的全局屬性。

          • request:指向Request對象
          • response:指向Response對象
          • req:指向Node的request對象
          • req:指向Node的response對象
          • app:指向App對象
          • state:用于在中間件傳遞信息。
          this.state.user = yield User.find(id);

          上面代碼中,user屬性存放在this.state對象上面,可以被另一個中間件讀取。
          context對象的全局方法。

          • throw():拋出錯誤,直接決定了HTTP回應(yīng)的狀態(tài)碼。
          • assert():如果一個表達(dá)式為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;

          6 錯誤處理機(jī)制

          Koa提供內(nèi)置的錯誤處理機(jī)制,任何中間件拋出的錯誤都會被捕捉到,引發(fā)向客戶端返回一個500錯誤,而不會導(dǎo)致進(jìn)程停止,因此也就不需要forever這樣的模塊重啟進(jìn)程。

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

          上面代碼中,中間件內(nèi)部拋出一個錯誤,并不會導(dǎo)致Koa應(yīng)用掛掉。Koa內(nèi)置的錯誤處理機(jī)制,會捕捉到這個錯誤。
          當(dāng)然,也可以額外部署自己的錯誤處理機(jī)制。

          app.use(function *() {   try {     yield saveResults();   } catch (err) {     this.throw(400, '數(shù)據(jù)無效');   } });

          上面代碼自行部署了try...catch代碼塊,一旦產(chǎn)生錯誤,就用this.throw方法拋出。該方法可以將指定的狀態(tài)碼和錯誤信息,返回給客戶端。
          對于未捕獲錯誤,可以設(shè)置error事件的監(jiān)聽函數(shù)。

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

          error事件的監(jiān)聽函數(shù)還可以接受上下文對象,作為第二個參數(shù)。

          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方法的兩個參數(shù),一個是錯誤碼,另一個是報錯信息。如果省略狀態(tài)碼,默認(rèn)是500錯誤。  this.assert方法用于在中間件之中斷言,用法類似于Node的assert模塊。  this.assert(this.user, 401, 'User not found. Please login!');

          上面代碼中,如果this.user屬性不存在,會拋出一個401錯誤。
          由于中間件是層級式調(diào)用,所以可以把try { yield next }當(dāng)成第一個中間件。

          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'); })

          7 cookie

          cookie的讀取和設(shè)置。

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

          get和set方法都可以接受第三個參數(shù),表示配置參數(shù)。其中的signed參數(shù),用于指定cookie是否加密。
          如果指定加密的話,必須用app.keys指定加密短語。

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

          this.cookie的配置對象的屬性如下。

          • signed:cookie是否加密。
          • expires:cookie何時過期
          • path:cookie的路徑,默認(rèn)是“/”。
          • domain:cookie的域名。
          • secure:cookie是否只有https請求下才發(fā)送。
          • httpOnly:是否只有服務(wù)器可以取到cookie,默認(rèn)為true。

          8 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');

          【推薦學(xué)習(xí):《nodejs 教程》】

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號