日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Mochiweb的設(shè)計(jì)分析

系統(tǒng) 2021 0

?

Mochiweb的設(shè)計(jì)分析

March 15th, 2009 :: refactor

轉(zhuǎn)自: http://erlang-china.org/misc/mochiweb-inside.html

Web服務(wù)器 的基本工作大致分3步:?

  1. 接收HTTP請求;?
  2. 處理HTTP請求,生成響應(yīng)內(nèi)容;
  3. 發(fā)送響應(yīng)

一、處理請求和發(fā)送響應(yīng) ?

模塊mochiweb_request可說是Mochiweb處理HTTP請求的核心部分,它總共負(fù)責(zé)了第2步和第3步工作。因此參數(shù)化模塊mochiweb_request的實(shí)例不像它的模塊名那樣單純:它還負(fù)責(zé)將請求的響應(yīng)(通過Socket連接,調(diào)用gen_tcp:send)發(fā)還(response)給瀏覽器。這個(gè)模塊是一個(gè) 參數(shù)化模塊 。這意味著它具有基于對象(Object-based)的特點(diǎn),它的每個(gè)實(shí)例化對象代表一個(gè)用戶請求,用戶可以像OO那樣操作HTTP請求:獲取請求信息,生成響應(yīng)內(nèi)容等。?

對靜態(tài)內(nèi)容(如html文件,靜態(tài)圖片)來說,無非是讀取文件系統(tǒng)中靜態(tài)文件的內(nèi)容作為響應(yīng)消息體(Body)發(fā)送給客戶端瀏覽器。?

對動(dòng)態(tài)內(nèi)容來說,生成響應(yīng)內(nèi)容的業(yè)務(wù)邏輯是用戶通過編程實(shí)現(xiàn)的:解析請求(包括URL路徑和HTTP請求頭),然后生成相應(yīng)的響應(yīng)內(nèi)容。用戶編寫業(yè)務(wù)邏輯處理函數(shù),然后將函數(shù)插入到mochiweb中。此函數(shù)帶有一參數(shù),該參數(shù)是參數(shù)化模塊mochiweb_request的實(shí)例(假設(shè)為Req),在這個(gè)定制函數(shù)中可以通過這個(gè)Req實(shí)例對象獲取瀏覽器請求的所有信息(包括URL路徑和HTTP請求頭),處理后的響應(yīng)數(shù)據(jù)也通過Req實(shí)例提供的函數(shù)發(fā)還給瀏覽器,有好幾種方式:?

  1. 通過Req實(shí)例對象直接發(fā)還給瀏覽器

    ?

      a)? 通過這個(gè)Req實(shí)例對象的response/1函數(shù)直接發(fā)還給瀏覽器:
      Req:response({Code, ResponseHeaders, Body})
      這個(gè)函數(shù)接收一個(gè)tuple參數(shù),參數(shù)的第一個(gè)元素是HTTP狀態(tài)碼(比如200),第二個(gè)元素是響應(yīng)消息頭列表(一個(gè)二元tuple,key和value都是字符串,如{“Content-Type”, “image/jpeg”}),第三個(gè)元素即為HTTP響應(yīng)內(nèi)容;如果是動(dòng)態(tài)內(nèi)容,采用response函數(shù)直接發(fā)還響應(yīng)數(shù)據(jù)還是比較方便的。

      b)? 如果是靜態(tài)文件,通過Req的serve_file(…)函數(shù)可以直接將文件發(fā)還給瀏覽器,告訴此函數(shù)文件的Web根目錄(doc_root)和相對路徑就可以將指定的靜態(tài)文件發(fā)給瀏覽器了。doc_root目錄一般在配置文件中設(shè)置,這個(gè)目錄下的所有文件都可以通過HTTP訪問。

      c)? 一些常見的例行響應(yīng):
      不存在的URL請求返回404錯(cuò)誤,可以直接調(diào)用Req:not_found() 若一切正常,調(diào)用Req:ok({…, Body})直接返回狀態(tài)碼為200的HTTP響應(yīng)
      b,c兩種情況的內(nèi)部其實(shí)還是調(diào)用的Req:response()

  2. 通過Response模塊對象將響應(yīng)發(fā)還給瀏覽器

    ?

      Req:response函數(shù)會返回一個(gè)mochiweb_response參數(shù)化模塊實(shí)例對象(假設(shè)為Response),Response實(shí)例對象包含有對應(yīng)的Req實(shí)例對象。通過Response對象可以得到響應(yīng)的相關(guān)信息(如響應(yīng)狀態(tài)碼,響應(yīng)消息頭,對應(yīng)的Req對象),它還有一個(gè)send函數(shù)可以將響應(yīng)數(shù)據(jù)發(fā)還給瀏覽器(它的實(shí)現(xiàn)其實(shí)還是調(diào)用Req對象的send函數(shù)進(jìn)行的)。Response之所以還要有send函數(shù)是為了發(fā)送chunked數(shù)據(jù)(HTTP 1.1)的方便,在第一次響應(yīng)完成后,后繼的chunk數(shù)據(jù)就可以通過最初返回的Response對象繼續(xù)進(jìn)行發(fā)送了,為此Response有個(gè)函數(shù)write_chunk()專門干這事,write_chunk檢查了請求消息頭中的HTTP 版本消息后就調(diào)用Response:send。

      因此,響應(yīng)內(nèi)容最終都是由參數(shù)化模塊mochiweb_request的response/1函數(shù)發(fā)送的。而這個(gè)response(…)函數(shù)內(nèi)部最后調(diào)用了Req:send(Data)函數(shù)將響應(yīng)通過socket連接(調(diào)用gen_tcp:send)返還給瀏覽器,這一發(fā)送過程又分成兩個(gè)階段:響應(yīng)消息頭(Headers)的發(fā)送和消息體(Body)的發(fā)送,這兩步都是通過Req:send完成的。

小結(jié):對于程序員來說,他編寫的服務(wù)器端處理HTTP請求的函數(shù)必須帶有一個(gè)參數(shù),這個(gè)參數(shù)代表了mochiweb_request參數(shù)化模塊的一個(gè)實(shí)例對象。通過這個(gè)實(shí)例程序員可以得到HTTP請求的所有信息(包括路徑、請求參數(shù)以及HTTP請求消息頭),然后生成響應(yīng),他還可以通過該mochiweb_request實(shí)例對象將響應(yīng)數(shù)據(jù)發(fā)還給瀏覽器。?

  • 如果響應(yīng)的是靜態(tài)文件,可以通過Request:server_file()函數(shù)發(fā)送響應(yīng);
  • 如果響應(yīng)是動(dòng)態(tài)生成的內(nèi)容,通過Request:response()函數(shù)發(fā)送響應(yīng)數(shù)據(jù)(文本數(shù)據(jù)和二進(jìn)制數(shù)據(jù)都可以);
  • 如果是chunk響應(yīng),第一次調(diào)用Request:response()函數(shù)發(fā)送數(shù)據(jù)后,該函數(shù)會返回一個(gè)Response實(shí)例對象(參數(shù)化模塊mochiweb_response的一個(gè)實(shí)例),以后的響應(yīng)數(shù)據(jù)可以通過這個(gè)Response實(shí)例對象(調(diào)用Response:write_chunk(Data))發(fā)送后續(xù)的響應(yīng)數(shù)據(jù)。

二、Web服務(wù)器的業(yè)務(wù)處理邏輯如何嵌入到Mochiweb ?

業(yè)務(wù)處理邏輯被程序員編寫成一個(gè)函數(shù)(函數(shù)式編程中函數(shù)也是一種數(shù)據(jù),以下稱為HttpLoop),處理函數(shù)HttpLoop是作為mochiweb啟動(dòng)時(shí)的參數(shù)之一進(jìn)入Mochiweb,Mochiweb是這樣啟動(dòng)的:?

mochiweb_http : start ([ { loop ,? HttpLoop },... ]) ??

Request實(shí)例對象最終要調(diào)用gen_tcp:send(Socket,…)將響應(yīng)數(shù)據(jù)由socket連接發(fā)給瀏覽器,因此,Request實(shí)例對象應(yīng)該持有HTTP請求的socket連接。這個(gè)目標(biāo)是這樣實(shí)現(xiàn)的:?
在啟動(dòng)過程中,mochiweb_http又對用戶的HttpLoop函數(shù)進(jìn)行了重新包裝?

Loop ?=? fun ? ( Socket ) ?->
?? ?
mochiweb_http : loop ( Socket ,? HttpLoop )
end ,

每個(gè)瀏覽器連接請求對應(yīng)著一個(gè)Socket連接,新的Loop函數(shù)以此Socket作為參數(shù),然后通過mochiweb_http:loop函數(shù)對Socket連接和用戶自定義的HttpLoop函數(shù)進(jìn)行了處理,簡單的說,這個(gè)函數(shù)做了如下工作:?

  1. 將Socket連接設(shè)置成能處理HTTP數(shù)據(jù)包 (inet:setopts(Socket, [{packet, http}]));
  2. 準(zhǔn)備接收socket連接傳來的數(shù)據(jù)(gen_tcp:recv(Socket,…));

當(dāng)收到數(shù)據(jù)時(shí):

  1. 將HTTP消息頭數(shù)據(jù)提出(成為{HeaderName, HeaderValue}的tuple列表)
  2. 生成一個(gè)參數(shù)化模塊mochiweb_request的實(shí)例對象,并將Socket連接、HTTP請求信息(路徑、請求方法、HTTP版本)以及請求消息頭列表包裝到此實(shí)例對象中,
  3. 然后調(diào)用用戶的HttpLoop對請求進(jìn)行處理和響應(yīng)(如前所述,處理得到的響應(yīng)數(shù)據(jù)也在用戶編寫的HttpLoop函數(shù)中被發(fā)送給瀏覽器)
  4. 最后根據(jù)HTTP請求信息決定是簡單的關(guān)閉Socket連接,還是清理一下Req對象并保持連接(例如對keep-alive,chunk等類型的HTTP請求,以及還沒完成數(shù)據(jù)傳送的HTTP請求),以便繼續(xù)讓HttpLoop函數(shù)進(jìn)行處理,

這都是在headers函數(shù)中進(jìn)行的,還是看mochiweb_http模塊的代碼:?

  1. headers ( Socket ,? Request ,? Headers ,? HttpLoop ,? HeaderCount ) ?->?
  2. ? ?? case ? gen_tcp : recv ( Socket ,? 0 , ? IDLE_TIMEOUT ) ? of ?
  3. ? ? ? ? { ok ,? http_eoh } ->?
  4. ? ? ? ? ? ?? inet : setopts ( Socket ,? [ { packet ,? raw } ]) ,?
  5. ? ? ? ? ? ?? % 將Socket連接、HTTP請求信息(路徑、請求方法、HTTP版本)以及請求消息頭列表打包成參數(shù)化模塊(mochiweb_request)的實(shí)例對象?
  6. ? ? ? ? ? ?? Req ?=? mochiweb : new_request ( { Socket ,? Request ,?
  7. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? lists : reverse ( Headers ) } ) ,? ?
  8. ? ? ? ? ? ?? HttpLoop ( Req ) ,? % 讓用戶編寫的函數(shù)處理HTTP請求?
  9. ? ? ? ? ??? case ? Req : should_close () ? of ?
  10. ? ? ? ? ? ? ? ?? true ?->??
  11. ? ? ? ? ? ? ? ? ? ?? gen_tcp : close ( Socket ) ,?
  12. ? ? ? ? ? ? ? ? ? ?? exit ( normal ) ;?
  13. ? ? ? ? ? ? ? ?? false ?->??
  14. ? ? ? ? ? ? ? ? ? ?? Req : cleanup () ,?
  15. ? ? ? ? ? ? ? ? ? ?? mochiweb_http : loop ( Socket ,? HttpLoop ) ?
  16. ? ? ? ? ? ?? end ;?
  17. ? ? ? ? { ok , { http_header ,? _ ,? Name ,? _ ,? Value }} ->?
  18. ? ? ? ? ? ?? headers ( Socket ,? Request ,? [ { margin-
分享到:
評論

Mochiweb的設(shè)計(jì)分析


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 柳河县| 肥东县| 宜章县| 临沧市| 长泰县| 龙州县| 秦安县| 时尚| 阳高县| 凤城市| 林口县| 虎林市| 彩票| 怀宁县| 黑龙江省| 彰化市| 玉溪市| 兴化市| 罗平县| 抚松县| 集贤县| 沂水县| 纳雍县| 沂源县| 贞丰县| 平凉市| 区。| 桐城市| 林口县| 集安市| 乐亭县| 北宁市| 万荣县| 修水县| 田阳县| 汤阴县| 保康县| 英山县| 静海县| 泸定县| 宁国市|