koa簡介


資料來源:
http://javascript.ruanyifeng.com/nodejs/koa.html
http://koa.bootcss.com/

以下內容為摘抄,純屬做筆記加深印象。勿噴。

 

使用 koa 編寫 web 應用,通過組合不同的 generator,可以免除重復繁瑣的回調函數嵌套,並極大地提升錯誤處理的效率。一個Koa應用就是一個對象,包含了一個middleware數組,這個數組由一組Generator函數組成。這些函數負責對HTTP請求進行各種加工,比如生成緩存、指定代理、請求重定向等等。這些中間件函數基於 request 請求以一個類似於棧的結構組成並依次執行。

Koa 包含了像 content-negotiation(內容協商)、cache freshness(緩存刷新)、proxy support(代理支持)和 redirection(重定向)等常用任務方法。 與提供龐大的函數支持不同,Koa只包含很小的一部分,因為Koa並不綁定任何中間件。

 

中間件

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

Generator函數內部使用yield命令,將程序的執行權轉交給下一個中間件,即yield next,要等到下一個中間件返回結果,才會繼續往下執行。只要有一個中間件缺少yield next語句,后面的中間件都不會執行,這一點要引起注意。

如果想跳過一個中間件,可以直接在該中間件的第一行語句寫上return yield next

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

由於Koa要求中間件唯一的參數就是next,導致如果要傳入其他參數,必須另外寫一個返回Generator函數的函數。

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

 

路由

可以通過this.path屬性,判斷用戶請求的路徑,從而起到路由作用。

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

復雜的路由需要安裝koa-router插件。

var app = require('koa')();
var Router = require('koa-router'); var myRouter = new Router(); myRouter.get('/', function *(next) { //router.get方法的第一個參數是根路徑,第二個參數是對應的函數方法。
  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()

這些動詞方法可以接受兩個參數,第一個是路徑模式,第二個是對應的控制器方法(中間件),定義用戶請求該路徑時服務器行為。

Koa-router允許為路徑統一添加前綴。
var router = new Router({
  prefix: '/users'
});

router.get('/', ...); // 等同於"/users"
router.get('/:id', ...); // 等同於"/users/:id"

 

app.listen(...)

Koa 應用並非是一個 1-to-1 表征關系的 HTTP 服務器。 一個或多個Koa應用可以被掛載到一起組成一個包含單一 HTTP 服務器的大型應用群。

如下為一個綁定3000端口的簡單 Koa 應用,其創建並返回了一個 HTTP 服務器。

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

 

app.callback()

返回一個適合 http.createServer() 方法的回調函數用來處理請求。 您也可以使用這個回調函數將您的app掛載在 Connect/Express 應用上。

 

app.use(function)

為應用添加指定的中間件,https://github.com/koajs/koa/wiki#middleware,也就是向middleware數組添加Generator函數。

 

app.keys=

設置簽名Cookie密鑰,該密鑰會被傳遞給 KeyGrip。

自己生成秘鑰實例:

app.keys = ['im a newer secret', 'i like turtle'];
app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256');

 

錯誤處理

默認情況下Koa會將所有錯誤信息輸出到 stderr,除非 NODE_ENV 是 "test"。為了實現自定義錯誤處理邏輯(比如 centralized logging),您可以添加 "error" 事件監聽器。

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

 

Context(上下文)

Koa Context 將 node 的 request 和 response 對象封裝在一個單獨的對象里面,其為編寫 web 應用和 API 提供了很多有用的方法。

context 在每個 request 請求中被創建,在中間件中作為接收器(receiver)來引用,或者通過 this 標識符來引用:

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

 

CSRF攻擊

CSRF攻擊是指用戶的session被劫持,用來冒充用戶的攻擊。

koa-csrf插件用來防止CSRF攻擊。原理是在session之中寫入一個秘密的token,用戶每次使用POST方法提交數據的時候,必須含有這個token,否則就會拋出錯誤。

 

數據壓縮

koa-compress模塊可以實現數據壓縮。

app.use(require('koa-compress')())
app.use(function* () {
  this.type = 'text/plain'
  this.body = fs.createReadStream('filename.txt')
})

 

API

  • ctx.req
    Node 的 request 對象。

  • ctx.res
    Node 的 response 對象。

  • ctx.request
    Koa 的 Request 對象。

  • ctx.response
    Koa 的 Response 對象。

  • ctx.app
    應用實例引用。

  • ctx.cookies.get(name, [options])
    獲得 cookie 中名為 name 的值,options 為可選參數:

    • 'signed': 如果為 true,表示請求時 cookie 需要進行簽名。
  • ctx.cookies.set(name, value, [options])
    設置 cookie 中名為 name 的值,options 為可選參數:

    • signed: 是否要做簽名
    • expires: cookie 有效期時間
    • path: cookie 的路徑,默認為 /'
    • domain: cookie 的域
    • secure: false 表示 cookie 通過 HTTP 協議發送,true 表示 cookie 通過 HTTPS 發送。
    • httpOnly: true 表示 cookie 只能通過 HTTP 協議發送
  • ctx.throw(msg, [status])
    拋出包含 .status 屬性的錯誤,默認為 500。該方法可以讓 Koa 准確的響應處理狀態。

 

請求(Request)API

Koa Request 對象是對 node 的 request 進一步抽象和封裝,提供了日常 HTTP 服務器開發中一些有用的功能。

  • req.header
    請求頭對象

  • req.method
    請求方法

  • req.method=
    設置請求方法,在實現中間件時非常有用,比如 methodOverride()。

  • req.length
    以數字的形式返回 request 的內容長度(Content-Length),或者返回 undefined。

  • req.url
    獲得請求url地址。

  • req.url=
    設置請求地址,用於重寫url地址時。

  • req.originalUrl
    獲取請求原始地址。

  • req.path
    獲取請求路徑名。

  • req.path=
    設置請求路徑名,並保留請求參數(就是url中?后面的部分)。

  • req.querystring
    獲取查詢參數字符串(url中?后面的部分),不包含 ?。

  • req.querystring=
    設置查詢參數。

  • req.search
    獲取查詢參數字符串,包含 ?。

  • req.search=
    設置查詢參數字符串。

  • req.host

  • req.hostname

  • req.charset

  • req.query
    將查詢參數字符串進行解析並以對象的形式返回,如果沒有查詢參數字字符串則返回一個空對象。

  • req.query=
    根據給定的對象設置查詢參數字符串。

  • req.fresh
    檢查請求緩存是否 "fresh"(內容沒有發生變化)。該方法用於在 If-None-Match / ETag, If-Modified-Since 和 Last-Modified 中進行緩存協調。當在 response headers 中設置一個或多個上述參數后,該方法應該被使用。

this.set('ETag', '123');

// cache is ok
if (this.fresh) {
  this.status = 304;
  return;
}

// cache is stale
// fetch new data
this.body = yield db.find('something');  
  • req.stale
    與 req.fresh 相反。

  • req.protocol
    返回請求協議,"https" 或者 "http"。 當 app.proxy 設置為 true 時,支持 X-Forwarded-Host。

  • req.secure
    簡化版 this.protocol == "https",用來檢查請求是否通過 TLS 發送。

  • req.ip
    請求遠程地址。 當 app.proxy 設置為 true 時,支持 X-Forwarded-Host。

  • req.is(type)
    檢查請求所包含的 "Content-Type" 是否為給定的 type 值。 如果沒有 request body,返回 undefined。 如果沒有 content type,或者匹配失敗,返回 false。 否則返回匹配的 content-type。

// With Content-Type: text/html; charset=utf-8
this.is('html'); // => 'html'
this.is('text/html'); // => 'text/html'
this.is('text/*', 'text/html'); // => 'text/html'

// When Content-Type is application/json
this.is('json', 'urlencoded'); // => 'json'
this.is('application/json'); // => 'application/json'
this.is('html', 'application/*'); // => 'application/json'

this.is('html'); // => false
  • req.accepts(types)
    檢查給定的類型 types(s) 是否可被接受,當為 true 時返回最佳匹配,否則返回 false。type 的值可以是一個或者多個 mime 類型字符串。

  • req.acceptsEncodings(encodings)
    檢查 encodings 是否可以被接受,當為 true 時返回最佳匹配,否則返回 false。 注意:您應該在 encodings 中包含 identity。

// Accept-Encoding: gzip
this.acceptsEncodings('gzip', 'deflate', 'identity');
// => "gzip"

this.acceptsEncodings(['gzip', 'deflate', 'identity']);
// => "gzip"
  • req.acceptsCharsets(charsets)
    檢查 charsets 是否可以被接受,如果為 true 則返回最佳匹配, 否則返回 false。
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
this.acceptsCharsets('utf-8', 'utf-7');
// => "utf-8"

this.acceptsCharsets(['utf-7', 'utf-8']);
// => "utf-8"
  • req.socket
    返回請求的socket。

  • req.get(field)
    返回請求 header 中對應 field 的值。

 

響應(Response)API

Koa Response 對象是對 node 的 response 進一步抽象和封裝,提供了日常 HTTP 服務器開發中一些有用的功能。

  • res.header
    Response header 對象。

  • res.socket
    Response socket。

  • res.status
    獲取 response status。不同於 node 在默認情況下 res.statusCode 為200,res.status 並沒有賦值。

  • res.statusString
    Response status 字符串。

  • res.status=
    通過數字狀態碼或者不區分大小寫的字符串來設置response status.

  • res.length=
    通過給定值設置 response Content-Length。

  • res.length
    如果 Content-Length 作為數值存在,或者可以通過 res.body 來進行計算,則返回相應數值,否則返回 undefined。

  • res.body
    獲得 response body。

  • res.body=

  • res.get(field)
    獲取 response header 中字段值,field 不區分大小寫。

var etag = this.get('ETag');
  • res.set(field, value)
    設置 response header 字段 field 的值為 value。
this.set('Cache-Control', 'no-cache');
  • res.set(fields)
    使用對象同時設置 response header 中多個字段的值。
this.set({
  'Etag': '1234',
  'Last-Modified': date
});
    • res.remove(field)
      移除 response header 中字段 filed。

    • res.type
      獲取 response Content-Type,不包含像 "charset" 這樣的參數。

    • res.type=
      通過 mime 類型的字符串或者文件擴展名設置 response Content-Type.

    • res.redirect(url, [alt])
      執行 [302] 重定向到對應 url。

    • res.lastModified
      如果存在 Last-Modified,則以 Date 的形式返回。

    • res.lastModified=
      以 UTC 格式設置 Last-Modified。您可以使用 Date 或 date 字符串來進行設置。

    • res.append(field, val)
      在 header 的 field 后面 追加 val。

    • res.vary(field)
      相當於執行res.append('Vary', field)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM