koa原始碼學習

2021-09-24 06:43:45 字數 4862 閱讀 3275

曾經看過很多原始碼,但是卻沒有本著刨根問底的精神,遇到不懂的問題總是輕易的放過。我知道掘金是個大神雲集的地方,希望把自己的學習過程記錄下來,一方面督促自己,一方面也是為了能和大家一起學習,分享自己學習的心得。

├── context.js

├── request.js

└── response.js

koa一共只有四個檔案,所以學習起來並不困難,稍微用一點時間就可以看完。從名稱上就可以看出各個檔案的功能。分別是請求,響應,上下文,應用四個檔案。

reuest.js是請求的封裝,包含發請求相關的一系列操作。

~的運用

判斷請求是否冪等。

get idempotent() 

複製**

首先解釋下冪等概念,冪等函式,或冪等方法,是指可以使用相同引數重複執行,並能獲得相同結果的函式。在http中,是指無論呼叫這個url多少次,都不會有不同的結果的http方法。這一部分如果有不理解的地方,可以看看這篇文章http請求方法及冪等性**。

比較好玩的地方是!!~methods.indexof()。

!!的作用是轉換為布林值,~的作用是按位取反。舉個例子js中-1的原碼為10..001(62個0),所以補碼為111..11(64)個1,按位取反後得到0。有這樣乙個規律,整數按位取反的結果等於-(x+1)。比較有意思的是 ~nan === -1, ~infinity === -1。

~~的運用

獲取content-length的長度,return number。

get length() 

複製**

由y=-(x+1),可以推出y==~~x。所以整數情況下,結果並不會發生改變。~~的引數不為整數時,會向下取整。當引數為nan,或infinity,以及非number型別時,都會返回0。這樣可以保證,返回的輸出的安全性。

x-forwarded-for欄位

get ips() 

複製**

這一部分的作用是獲得真實的使用者ip。x-forwarded-for:簡稱xff頭,它代表客戶端,也就是http的請求端真實的ip。如果乙個 http 請求到達伺服器之前,經過了三個** proxy1、proxy2、proxy3,ip 分別為 ip1、ip2、ip3,使用者真實 ip 為 ip0,那麼按照 xff 標準,服務端最終會收到以下資訊: x-forwarded-for: ip0,ip1,ip2。ip3不在這個列表中,因為ip3會通過remote address 字段獲得。

response.js是對原生req進行的封裝。

content-disposition屬性

attachment(filename) ,

複製**

其中extname是node的原生方法,獲得檔案的副檔名。主要需要搞清楚的是content-disposition欄位。

在multipart/form-data型別的應答訊息體中, content-disposition訊息頭可以被用在multipart訊息體的子部分中,用來給出其對應欄位的相關資訊。第乙個引數固定為form-data。詳細文件可以參考mdn。

etag欄位

set etag(val) "`;

this.set('etag', val);

}複製**

etag是資源的指紋,用來標識資源是否更改。和etag相比較的是if-match,和if-none-match響應首部。有關響應首部有不理解的朋友可以看看http條件請求。

當首部是if-match時,在請求方法為 get 和 head 的情況下,伺服器僅在請求的資源滿足此首部列出的 etag 之一時才會返回資源。而對於 put 或其他非安全方法來說,只有在滿足條件的情況下才可以將資源上傳。

當響應首部是if-none-match時,對於get 和 head 請求方法來說,當且僅當伺服器上沒有任何資源的 etag 屬性值與這個首部中列出的相匹配的時候,伺服器端會才返回所請求的資源,響應碼為 200。對於get和head不對伺服器狀態發生改變的方法,如果相匹配返回304,其他的返回則返回 412。

vary欄位

vary(field) 

複製**

這裡主要講一下vary的作用。

http中有乙個內容協商機制,為同乙個url指向的資源提供不同的展現形式。比如文件的自然語言,編碼形式,以及壓縮演算法等等。這種協商機制可以分為兩種形式展現:

vary欄位就是標誌伺服器在服務端驅動型內容協商階段所使用的首部清單,他可以通知快取伺服器決策的依據。常見的首部清單有accept,accept-language,accept-charset,accept-encoding,user-agent等。

content-length計算

get length() 

return ~~len;

}複製**

buffer.bytelength方法返回字串實際佔據的位元組長度,預設編碼方式為utf8。即使對於string型別,也沒有使用string.length來直接獲取,因為string.length獲取到的是字元的長度,而不是位元組長度。比如漢字,utf8編碼乙個字元就要佔三個位元組。

ctx是我們日常開發中最常用到的屬性,比如ctx.req,ctx.res,ctx.response,ctx.request。以及開發中介軟體時的各種操作,都是在ctx上完成的。

context原型上有inspect,tojson,assert,throw,和onerror五個方法。剩下的就是response和request的**。這裡用了乙個比較有意思的庫delegates。寫起來就像這樣

delegate(proto, 'response')

.method('attachment')

.method('redirect')

.method('remove')

.method('vary')

.method('set')

.method('flushheaders')

.access('status')

.access('message')

.access('body')

.access('length')

.access('type')

.access('lastmodified')

.access('etag')

.getter('headersent')

.getter('writable');

複製**

這裡使用鏈式操作,看起來非常簡單明瞭。 delegates中的getter和setter使用的是object.prototype.definegetter()和object.prototype.definesetter()方法。以setter舉例:

delegator.prototype.setter = function(name));

return

this;

};複製**

當我們為proto的某一屬性賦值時,其實還是呼叫target的set訪問器,這裡僅僅是乙個**。

callback() ;

return handlerequest;

}複製**

首先將middleware轉化為function,並構建ctx物件,隨後呼叫this.handlerequest傳入ctx,fn,處理請求。

this.handlerequest函式主幹如下所示:

handlerequest(ctx, fnmiddleware) 

複製**

fnmiddleware由compose函式得來,compose函式實現為下:

function

compose (middleware) ))

} catch (err) }}

}複製**

呼叫compose,返回乙個(context,next)=>{}的函式,也就是this.handlerequest中的fnmiddleware。當執行fnmiddleware時,返回dispatch(0)。執行dispatch時,返回乙個promise,當promise完成時,呼叫dispatch(1),以此類推,直到i === middleware.length時,fn = next,因為在this.handlerequest呼叫時,next並沒有傳,所以,此時fn === undefined, return promise.resolve();到這裡compose的邏輯算是理清了。我們在來看一下中介軟體是怎麼書寫的,舉乙個簡單的例子:

const one = (ctx, next) => 

const two = (ctx, next) =>

複製**

執行dispatch(0)時,返回

return

promise.resolve(one(context, function

next () ))

複製**

當執行到one函式的next函式時,此時return到dispatch(1)。此時dispatch(1)執行,當執行到two的next時,返回dispatch(2)。因為2 === middleware.length,又因為fn == undefined,固此時return promise.resolve()。當two的next方法執行完畢,繼續執行console.log('<< two')。當two的函式全部執行完畢後,程式回到one的next()結束部分,繼續執行console.log('<< one')。async await非同步函式執行同理。

這一塊的邏輯確實難於理解,可以打斷點除錯下看看結果。

總結一下:學習不光要多看,還要多寫,還要多實踐,這樣才能真正理解,並有所收穫!

Koa2原始碼學習

koa 基於 node.js 平台的下一代 web 開發框架 const koa require koa do some thing 以上 構建了乙個簡單的伺服器,你可以在瀏覽器輸入 localhost 8080 來訪問 下面我們通過建立koa伺服器,且傳送一次http請求來了解原始碼 在koa例項...

Koa原始碼分析

上篇文章寫了如何閱讀koa的原始碼,粗略的過了一下koa的原始碼,但是作為乙個沒有得出乙個具體的結論,中介軟體的執行原理也不清楚,這裡我們再仔細的過一遍koa的原始碼.首先還是先過一遍例子 const koa require koa ctx.body hello world 複製 起乙個web服務,...

Koa原始碼分析

先看看這個極簡的啟動 const koa require koa response ctx.body hello koa 我們在koa原始碼資料夾下建立index.js檔案,將上面的 寫入,並將require koa 換成require const koa require debugger ctx....