<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ### 相關結構體 (90%)[](http://tengine.taobao.org/book/chapter_04.html#id7 "永久鏈接至標題") ngx_chain_t 結構非常簡單,是一個單向鏈表: typedef struct ngx_chain_s ngx_chain_t; struct ngx_chain_s { ngx_buf_t *buf; ngx_chain_t *next; }; 在過濾模塊中,所有輸出的內容都是通過一條單向鏈表所組成。這種單向鏈表的設計,正好應和了Nginx流式的輸出模式。每次Nginx都是讀到一部分的內容,就放到鏈表,然后輸出出去。這種設計的好處是簡單,非阻塞,但是相應的問題就是跨鏈表的內容操作非常麻煩,如果需要跨鏈表,很多時候都只能緩存鏈表的內容。 單鏈表負載的就是ngx_buf_t,這個結構體使用非常廣泛,先讓我們看下該結構體的代碼: struct ngx_buf_s { u_char *pos; /* 當前buffer真實內容的起始位置 */ u_char *last; /* 當前buffer真實內容的結束位置 */ off_t file_pos; /* 在文件中真實內容的起始位置 */ off_t file_last; /* 在文件中真實內容的結束位置 */ u_char *start; /* buffer內存的開始分配的位置 */ u_char *end; /* buffer內存的結束分配的位置 */ ngx_buf_tag_t tag; /* buffer屬于哪個模塊的標志 */ ngx_file_t *file; /* buffer所引用的文件 */ /* 用來引用替換過后的buffer,以便當所有buffer輸出以后, * 這個影子buffer可以被釋放。 */ ngx_buf_t *shadow; /* the buf's content could be changed */ unsigned temporary:1; /* * the buf's content is in a memory cache or in a read only memory * and must not be changed */ unsigned memory:1; /* the buf's content is mmap()ed and must not be changed */ unsigned mmap:1; unsigned recycled:1; /* 內存可以被輸出并回收 */ unsigned in_file:1; /* buffer的內容在文件中 */ /* 馬上全部輸出buffer的內容, gzip模塊里面用得比較多 */ unsigned flush:1; /* 基本上是一段輸出鏈的最后一個buffer帶的標志,標示可以輸出, * 有些零長度的buffer也可以置該標志 */ unsigned sync:1; /* 所有請求里面最后一塊buffer,包含子請求 */ unsigned last_buf:1; /* 當前請求輸出鏈的最后一塊buffer */ unsigned last_in_chain:1; /* shadow鏈里面的最后buffer,可以釋放buffer了 */ unsigned last_shadow:1; /* 是否是暫存文件 */ unsigned temp_file:1; /* 統計用,表示使用次數 */ /* STUB */ int num; }; 一般buffer結構體可以表示一塊內存,內存的起始和結束地址分別用start和end表示,pos和last表示實際的內容。如果內容已經處理過了,pos的位置就可以往后移動。如果讀取到新的內容,last的位置就會往后移動。所以buffer可以在多次調用過程中使用。如果last等于end,就說明這塊內存已經用完了。如果pos等于last,說明內存已經處理完了。下面是一個簡單的示意圖,說明buffer中指針的用法: ![](https://box.kancloud.cn/2015-08-12_55cb06b1f16ed.png) ### 響應頭過濾函數 (90%)[](http://tengine.taobao.org/book/chapter_04.html#id8 "永久鏈接至標題") 響應頭過濾函數主要的用處就是處理HTTP響應的頭,可以根據實際情況對于響應頭進行修改或者添加刪除。響應頭過濾函數先于響應體過濾函數,而且只調用一次,所以一般可作過濾模塊的初始化工作。 響應頭過濾函數的入口只有一個: ngx_int_t ngx_http_send_header(ngx_http_request_t *r) { ... return ngx_http_top_header_filter(r); } 該函數向客戶端發送回復的時候調用,然后按前一節所述的執行順序。該函數的返回值一般是NGX_OK,NGX_ERROR和NGX_AGAIN,分別表示處理成功,失敗和未完成。 你可以把HTTP響應頭的存儲方式想象成一個hash表,在Nginx內部可以很方便地查找和修改各個響應頭部,ngx_http_header_filter_module過濾模塊把所有的HTTP頭組合成一個完整的buffer,最終ngx_http_write_filter_module過濾模塊把buffer輸出。 按照前一節過濾模塊的順序,依次講解如下: | filter module | description | |-----|-----| | ngx_http_not_modified_filter_module | 默認打開,如果請求的if-modified-since等于回復的last-modified間值,說明回復沒有變化,清空所有回復的內容,返回304。 | | ngx_http_range_body_filter_module | 默認打開,只是響應體過濾函數,支持range功能,如果請求包含range請求,那就只發送range請求的一段內容。 | | ngx_http_copy_filter_module | 始終打開,只是響應體過濾函數, 主要工作是把文件中內容讀到內存中,以便進行處理。 | | ngx_http_headers_filter_module | 始終打開,可以設置expire和Cache-control頭,可以添加任意名稱的頭 | | ngx_http_userid_filter_module | 默認關閉,可以添加統計用的識別用戶的cookie。 | | ngx_http_charset_filter_module | 默認關閉,可以添加charset,也可以將內容從一種字符集轉換到另外一種字符集,不支持多字節字符集。 | | ngx_http_ssi_filter_module | 默認關閉,過濾SSI請求,可以發起子請求,去獲取include進來的文件 | | ngx_http_postpone_filter_module | 始終打開,用來將子請求和主請求的輸出鏈合并 | | ngx_http_gzip_filter_module | 默認關閉,支持流式的壓縮內容 | | ngx_http_range_header_filter_module | 默認打開,只是響應頭過濾函數,用來解析range頭,并產生range響應的頭。 | | ngx_http_chunked_filter_module | 默認打開,對于HTTP/1.1和缺少content-length的回復自動打開。 | | ngx_http_header_filter_module | 始終打開,用來將所有header組成一個完整的HTTP頭。 | | ngx_http_write_filter_module | 始終打開,將輸出鏈拷貝到r->out中,然后輸出內容。 | ### 響應體過濾函數?[](http://tengine.taobao.org/book/chapter_04.html#id9 "永久鏈接至標題") 響應體過濾函數是過濾響應主體的函數。ngx_http_top_body_filter這個函數每個請求可能會被執行多次,它的入口函數是ngx_http_output_filter,比如: ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_connection_t *c; c = r->connection; rc = ngx_http_top_body_filter(r, in); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ c->error = 1; } return rc; } ngx_http_output_filter可以被一般的靜態處理模塊調用,也有可能是在upstream模塊里面被調用,對于整個請求的處理階段來說,他們處于的用處都是一樣的,就是把響應內容過濾,然后發給客戶端。 具體模塊的響應體過濾函數的格式類似這樣: static int ngx_http_example_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ... return ngx_http_next_body_filter(r, in); } 該函數的返回值一般是NGX_OK,NGX_ERROR和NGX_AGAIN,分別表示處理成功,失敗和未完成。 #### 主要功能介紹?[](http://tengine.taobao.org/book/chapter_04.html#id10 "永久鏈接至標題") 響應的主體內容就存于單鏈表in,鏈表一般不會太長,有時in參數可能為NULL。in中存有buf結構體中,對于靜態文件,這個buf大小默認是32K;對于反向代理的應用,這個buf可能是4k或者8k。為了保持內存的低消耗,Nginx一般不會分配過大的內存,處理的原則是收到一定的數據,就發送出去。一個簡單的例子,可以看看Nginx的chunked_filter模塊,在沒有content-length的情況下,chunk模塊可以流式(stream)的加上長度,方便瀏覽器接收和顯示內容。 在響應體過濾模塊中,尤其要注意的是buf的標志位,完整描述可以在“相關結構體”這個節中看到。如果buf中包含last標志,說明是最后一塊buf,可以直接輸出并結束請求了。如果有flush標志,說明這塊buf需要馬上輸出,不能緩存。如果整塊buffer經過處理完以后,沒有數據了,你可以把buffer的sync標志置上,表示只是同步的用處。 當所有的過濾模塊都處理完畢時,在最后的write_fitler模塊中,Nginx會將in輸出鏈拷貝到r->out輸出鏈的末尾,然后調用sendfile或者writev接口輸出。由于Nginx是非阻塞的socket接口,寫操作并不一定會成功,可能會有部分數據還殘存在r->out。在下次的調用中,Nginx會繼續嘗試發送,直至成功。 #### 發出子請求[](http://tengine.taobao.org/book/chapter_04.html#id11 "永久鏈接至標題") Nginx過濾模塊一大特色就是可以發出子請求,也就是在過濾響應內容的時候,你可以發送新的請求,Nginx會根據你調用的先后順序,將多個回復的內容拼接成正常的響應主體。一個簡單的例子可以參考addition模塊。 Nginx是如何保證父請求和子請求的順序呢?當Nginx發出子請求時,就會調用ngx_http_subrequest函數,將子請求插入父請求的r->postponed鏈表中。子請求會在主請求執行完畢時獲得依次調用。子請求同樣會有一個請求所有的生存期和處理過程,也會進入過濾模塊流程。 關鍵點是在postpone_filter模塊中,它會拼接主請求和子請求的響應內容。r->postponed按次序保存有父請求和子請求,它是一個鏈表,如果前面一個請求未完成,那后一個請求內容就不會輸出。當前一個請求完成時并輸出時,后一個請求才可輸出,當所有的子請求都完成時,所有的響應內容也就輸出完畢了。 #### 一些優化措施?[](http://tengine.taobao.org/book/chapter_04.html#id12 "永久鏈接至標題") Nginx過濾模塊涉及到的結構體,主要就是chain和buf,非常簡單。在日常的過濾模塊中,這兩類結構使用非常頻繁,Nginx采用類似freelist重復利用的原則,將使用完畢的chain或者buf結構體,放置到一個固定的空閑鏈表里,以待下次使用。 比如,在通用內存池結構體中,pool->chain變量里面就保存著釋放的chain。而一般的buf結構體,沒有模塊間公用的空閑鏈表池,都是保存在各模塊的緩存空閑鏈表池里面。對于buf結構體,還有一種busy鏈表,表示該鏈表中的buf都處于輸出狀態,如果buf輸出完畢,這些buf就可以釋放并重復利用了。 | 功能 | 函數名 | |-----|-----| | chain分配 | ngx_alloc_chain_link | | chain釋放 | ngx_free_chain | | buf分配 | ngx_chain_get_free_buf | | buf釋放 | ngx_chain_update_chains | #### 過濾內容的緩存?[](http://tengine.taobao.org/book/chapter_04.html#id13 "永久鏈接至標題") 由于Nginx設計流式的輸出結構,當我們需要對響應內容作全文過濾的時候,必須緩存部分的buf內容。該類過濾模塊往往比較復雜,比如sub,ssi,gzip等模塊。這類模塊的設計非常靈活,我簡單講一下設計原則: 1. 輸入鏈in需要拷貝操作,經過緩存的過濾模塊,輸入輸出鏈往往已經完全不一樣了,所以需要拷貝,通過ngx_chain_add_copy函數完成。 1. 一般有自己的free和busy緩存鏈表池,可以提高buf分配效率。 1. 如果需要分配大塊內容,一般分配固定大小的內存卡,并設置recycled標志,表示可以重復利用。 1. 原有的輸入buf被替換緩存時,必須將其buf->pos設為buf->last,表明原有的buf已經被輸出完畢。或者在新建立的buf,將buf->shadow指向舊的buf,以便輸出完畢時及時釋放舊的buf。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看