request
在nginx中我們指的是http請求,一個http請求瞄摊,包含請求行勋又、請求頭、請求體换帜、響應行楔壤、響應頭、響應體惯驼。具體到nginx中的數據結構是ngx_http_request_t蹲嚣,ngx_http_request_t是對一個http請求的封裝。
完整的請求處理
http請求是典型的請求-響應類型的的網絡協議祟牲,而http是文件協議隙畜,所以我們在分析請求行與請求頭,以及輸出響應行與響應頭说贝,往往是一行一行的進行處理禾蚕。如果我們自己來寫一個http服務器,通常在一個連接建立好后狂丝,客戶端會發(fā)送請求過來换淆。然后我們讀取一行數據,分析出請求行中包含的method几颜、uri倍试、http_version信息。然后再一行一行處理請求頭蛋哭,并根據請求method與請求頭的信息來決定是否有請求體以及請求體的長度县习,然后再去讀取請求體。得到請求后谆趾,我們處理請求產生需要輸出的數據躁愿,然后再生成響應行,響應頭以及響應體沪蓬。在將響應發(fā)送給客戶端之后彤钟,一個完整的請求就處理完了。
當然這是最簡單的webserver的處理方式跷叉,其實nginx也是這樣做的逸雹,只是有一些小小的區(qū)別,比如云挟,當請求頭讀取完成后梆砸,就開始進行請求的處理了。nginx通過ngx_http_request_t來保存解析請求與輸出響應相關的數據园欣。
nginx是如何處理一個完整的請求
對于nginx來說帖世,一個請求是從ngx_http_init_request開始的。在這個函數中沸枯,會設置讀事件為ngx_http_process_request_line日矫,也就是說,接下來的網絡事件辉饱,會由ngx_http_process_request_line來執(zhí)行搬男,處理請求行。
處理請求的第一件事就是處理請求行彭沼,通過ngx_http_read_request_header來讀取請求數據缔逛。然后調用ngx_http_parse_request_line函數來解析請求行。整個請求行解析到的參數姓惑,會保存到ngx_http_request_t結構當中褐奴。
在解析完請求行后,nginx會設置讀事件的handler為ngx_http_process_request_headers于毙,用來讀取請求頭敦冬,然后后續(xù)的請求就在ngx_http_process_request_headers中進行讀取與解析。解析到的請求頭會保存到ngx_http_request_t的域headers_in中唯沮,headers_in是一個鏈表結構脖旱,保存所有的請求頭堪遂。
而HTTP中有些請求是需要特別處理的,這些請求頭與請求處理函數存放在一個映射表里面萌庆,即ngx_http_headers_in溶褪,在初始化時,會生成一個hash表践险,當每解析到一個請求頭后猿妈,就會先在這個hash表中查找,如果有找到巍虫,則調用相應的處理函數來處理這個請求頭彭则。比如:Host頭的處理函數是ngx_http_process_host。
當nginx解析到兩個回車換行符時占遥,就表示請求頭的結束俯抖,此時就會調用ngx_http_process_request來處理請求了香罐。
ngx_http_process_request會設置當前的連接的讀寫事件處理函數為ngx_http_request_handler脆荷,然后再調用ngx_http_handler來真正開始處理一個完整的http請求。
真正開始處理數據晌砾,是在ngx_http_handler這個函數里面凛捏,這個函數會設置write_event_handler為ngx_http_core_run_phases担忧,并執(zhí)行ngx_http_core_run_phases函數。nginx將一個http請求的處理分為多個階段坯癣,ngx_http_core_run_phases這個函數將執(zhí)行多階段請求處理來產生數據瓶盛。
nginx的各種階段會對請求進行處理,最后會調用filter來過濾數據示罗,對數據進行加工惩猫。filter是一個鏈表結構,分別有header filter與body filter蚜点,先執(zhí)行header filter中的所有filter轧房,然后再執(zhí)行body filter中的所有filter。
在header filter中的最后一個filter绍绘,即ngx_http_header_filter奶镶,這個filter將會遍歷所有的響應頭,最后需要輸出的響應頭在一個連續(xù)的內存陪拘,然后調用ngx_http_write_filter進行輸出厂镇。ngx_http_write_filter是body filter中的最后一個,所以nginx首先的body信息左刽,在經過一系列的body filter之后捺信,最后也會調用ngx_http_write_filter來進行輸出
注意:
nginx會將整個請求頭都放在一個buffer里面,buffer的大小通過配置項client_header_buffer_size
來設置欠痴,如果用戶的請求頭太大迄靠,buffer裝不下秒咨,那nginx就會重新分配一個新的更大的buffer來裝請求
頭,這個大buffer可以通過large_client_header_buffers來設置梨水。為了保存請求行或請求頭的完整性拭荤,
一個完整的請求行或請求頭,需要放在一個連續(xù)的內存里面疫诽,所以,一個完整的請求行或請求頭旦委,只會保存
在一個buffer里面奇徒。這樣,如果請求行大于一個buffer的大小缨硝,就會返回414錯誤摩钙,如果一個請求頭大小
大于一個buffer大小,就會返回400錯誤查辩。
長連接
http請求是基于TCP協議之上的胖笛,當客戶端在發(fā)起請求前,需要先與服務端建立TCP連接宜岛,而每一次的TCP連接是需要三次握手來確定的长踊,如果客戶端與服務端之間網絡差一點,這三次交互消費的時間會比較多萍倡,而且三次交互也會帶來網絡流量身弊。當然,當連接斷開后列敲,也會有四次的交互阱佛。
而http請求是請求應答式的,如果我們能知道每個請求頭與響應體的長度戴而,那么我們是可以在一個連接上面執(zhí)行多個請求的凑术,這就是所謂的長連接,但前提條件是我們先得確定請求頭與響應體的長度所意。
對于請求來說淮逊,如果當前請求需要有body,如POST請求扁眯,那么nginx就需要客戶端在請求頭中指定content-length來表明body的大小壮莹,否則返回400錯誤。也就是說姻檀,請求體的長度是確定的命满。
http協議中關于響應body長度的確定:
對于http1.0協議來說,如果響應頭中有content-length頭绣版,則以content-length的長度就可以知道body的長度了胶台,客戶端在接收body時歼疮,就可以依照這個長度來接收數據,接收完后诈唬,就表示這個請求完成了韩脏。而如果沒有content-length頭,則客戶端會一直接收數據铸磅,直到服務端主動斷開連接赡矢,才表示body接收完了。
而對于http1.1協議來說阅仔,如果響應頭中的Transfer-encoding為chunked傳輸吹散,則表示body是流式輸出,body會被分成多個塊八酒,每塊的開始會標識出當前塊的長度空民,此時,body不需要通過長度來指定羞迷。如果是非chunked傳輸界轩,而且有content-length,則按照content-length來接收數據衔瓮。否則浊猾,如果是非chunked,并且沒有content-length报辱,則客戶端接收數據与殃,直到服務端主動斷開連接。
由此可知碍现,除了http1.0不帶content-length以及http1.1非chunked不帶content-length外幅疼,body的長度是可知的。此時昼接,當服務端在輸出完body之后爽篷,會可以考慮使用長連接。
Keepalive
能否使用長連接慢睡,也是有條件限制的逐工。
如果客戶端的請求頭中的connection為close,則表示客戶端需要關掉長連接漂辐,如果為keepalive泪喊,則客戶端需要打開長連接,如果客戶端的請求中沒有connection這個頭髓涯,那么根據協議袒啼,如果是http1.0,則默認為close,如果是http1.1蚓再,則默認為keepalive滑肉。如果結果為keepalive,那么摘仅,nginx在輸出完響應體后靶庙,會設置當前連接的keepalive屬性,然后等待客戶端下一次請求娃属。
當然六荒,nginx不可能一直等待下去,為了防止客戶端一直不發(fā)數據過來矾端,始終占用這個連接恬吕。當nginx設置了keepalive等待下一次的請求時,同時也會設置一個最大等待時間须床,這個時間是通過選項keepalive_timeout來配置的,如果配置為0渐裂,則表示關掉keepalive豺旬,此時,http版本無論是1.1還是1.0柒凉,客戶端的connection不管是close還是keepalive族阅,都會強制為close。
如果服務端最后的決定是keepalive打開膝捞,那么在響應的http頭里面坦刀,也會包含有connection頭域,其值是”Keep-Alive”蔬咬,否則就是”Close”鲤遥。如果connection值為close,那么在nginx響應完數據后林艘,會主動關掉連接盖奈。所以,對于請求量比較大的nginx來說狐援,關掉keepalive最后會產生比較多的time-wait狀態(tài)的socket钢坦。一般來說,當客戶端的一次訪問啥酱,需要多次訪問同一個server時爹凹,打開keepalive的優(yōu)勢非常大。
pipe
在http1.1中镶殷,引入了一種新的特性禾酱,即pipeline。其實就是流水線作業(yè),它可以看作為keepalive的一種升華宇植,因為pipeline也是基于長連接的得封,目的就是利用一個連接做多次請求。如果客戶端要提交多個請求指郁,對于keepalive來說忙上,那么第二個請求,必須要等到第一個請求的響應接收完全后闲坎,才能發(fā)起疫粥。
而對pipeline來說,客戶端不必等到第一個請求處理完后腰懂,就可以馬上發(fā)起第二個請求梗逮。nginx是直接支持pipeline的,但是绣溜,nginx對pipeline中的多個請求的處理卻不是并行的慷彤,依然是一個請求接一個請求的處理,只是在處理第一個請求的時候怖喻,客戶端就可以發(fā)起第二個請求底哗。這樣,nginx利用pipeline減少了處理完一個請求后锚沸,等待第二個請求的請求頭數據的時間跋选。
nginx的做法很簡單,前面說到哗蜈,nginx在讀取數據時前标,會將讀取的數據放到一個buffer里面,所以距潘,如果nginx在處理完前一個請求后炼列,如果發(fā)現buffer里面還有數據,就認為剩下的數據是下一個請求的開始绽昼,然后就接下來處理下一個請求唯鸭,否則就設置keepalive。
nginx要關閉連接時硅确,并非立即關閉連接目溉,而是先關閉tcp連接的寫,再等待一段時間后再關掉連接的讀菱农。為什么要這樣呢缭付?
我們先來看看這樣一個場景。nginx在接收客戶端的請求時循未,可能由于客戶端或服務端出錯了陷猫,要立即響應錯誤信息給客戶端秫舌,而nginx在響應錯誤信息后,大分部情況下是需要關閉當前連接绣檬。
nginx執(zhí)行完write()系統(tǒng)調用把錯誤信息發(fā)送給客戶端足陨,write()系統(tǒng)調用返回成功并不表示數據已經發(fā)送到客戶端,有可能還在tcp連接的write buffer里娇未。接著如果直接執(zhí)行close()系統(tǒng)調用關閉tcp連接墨缘,內核會首先檢查tcp的read buffer里有沒有客戶端發(fā)送過來的數據留在內核態(tài)沒有被用戶態(tài)進程讀取,如果有則發(fā)送給客戶端RST報文來關閉tcp連接丟棄write buffer里的數據零抬,如果沒有則等待write buffer里的數據發(fā)送完畢镊讼,然后再經過正常的4次分手報文斷開連接。
所以,當在某些場景下出現tcp write buffer里的數據在write()系統(tǒng)調用之后到close()系統(tǒng)調用執(zhí)行之前沒有發(fā)送完畢平夜,且tcp read buffer里面還有數據沒有讀蝶棋,close()系統(tǒng)調用會導致客戶端收到RST報文且不會拿到服務端發(fā)送過來的錯誤信息數據。那客戶端肯定會想忽妒,這服務器好霸道玩裙,動不動就reset我的連接,連個錯誤信息都沒有段直。
在上面這個場景中献酗,我們可以看到,關鍵點是服務端給客戶端發(fā)送了RST包坷牛,導致自己發(fā)送的數據在客戶端忽略掉了。所以很澄,解決問題的重點是京闰,讓服務端別發(fā)RST包。再想想甩苛,我們發(fā)送RST是因為我們關掉了連接蹂楣,關掉連接是因為我們不想再處理此連接了,也不會有任何數據產生了讯蒲。
對于全雙工的TCP連接來說痊土,我們只需要關掉寫就行了,讀可以繼續(xù)進行墨林,我們只需要丟掉讀到的任何數據就行了赁酝,這樣的話,當我們關掉連接后旭等,客戶端再發(fā)過來的數據酌呆,就不會再收到RST了。
當然最終我們還是需要關掉這個讀端的搔耕,所以我們會設置一個超時時間隙袁,在這個時間過后,就關掉讀,客戶端再發(fā)送數據來就不管了菩收,作為服務端我會認為梨睁,都這么長時間了,發(fā)給你的錯誤信息也應該讀到了娜饵,再慢就不關我事了坡贺,要怪就怪你RP不好了。
當然划咐,正常的客戶端拴念,在讀取到數據后,會關掉連接褐缠,此時服務端就會在超時時間內關掉讀端政鼠。
lingering_close
lingering_close存在的意義就是來讀取剩下的客戶端發(fā)來的數據,所以nginx會有一個讀超時時間队魏,通過lingering_timeout選項來設置公般,如果在lingering_timeout時間內還沒有收到數據,則直接關掉連接胡桨。
nginx還支持設置一個總的讀取時間官帘,通過lingering_time來設置,這個時間也就是nginx在關閉寫之后昧谊,保留socket的時間刽虹,客戶端需要在這個時間內發(fā)送完所有的數據,否則nginx在這個時間過后呢诬,會直接關掉連接涌哲。當然,nginx是支持配置是否打開lingering_close選項的尚镰,通過lingering_close選項來配置阀圾。
基本數據結構
ngx_str_t
在nginx源碼目錄的src/core下面的ngx_string.h|c里面,包含了字符串的封裝以及字符串相關操作的api狗唉。nginx提供了一個帶長度的字符串結構ngx_str_t 初烘。
ngx_pool_t
它提供了一種機制,幫助管理一系列的資源(如內存分俯,文件等)肾筐,使得對這些資源的使用和釋放統(tǒng)一進行,免除了使用過程中考慮到對各種各樣資源的什么時候釋放缸剪,是否遺漏了釋放的擔心局齿。
例如對于內存的管理,如果我們需要使用內存橄登,那么總是從一個ngx_pool_t的對象中獲取內存抓歼,在最終的某個時刻讥此,我們銷毀這個ngx_pool_t對象,所有這些內存都被釋放了谣妻。這樣我們就不必要對對這些內存進行malloc和free的操作萄喳,不用擔心是否某塊被malloc出來的內存沒有被釋放。因為當ngx_pool_t對象被銷毀的時候蹋半,所有從這個對象中分配出來的內存都會被統(tǒng)一釋放掉他巨。
ngx_array_t
ngx_array_t是nginx內部使用的數組結構。nginx的數組結構在存儲上與大家認知的C語言內置的數組有相似性减江,比如實際上存儲數據的區(qū)域也是一大塊連續(xù)的內存染突。但是數組除了存儲數據的內存以外還包含一些元信息來描述相關的一些信息。
ngx_hash_t
ngx_hash_t是nginx自己的hash表的實現辈灼。定義和實現位于src/core/ngx_hash.h|c中份企。ngx_hash_t的實現也與數據結構教科書上所描述的hash表的實現是大同小異。對于常用的解決沖突的方法有線性探測巡莹,二次探測和開鏈法等司志。ngx_hash_t使用的是最常用的一種,也就是開鏈法降宅,這也是STL中的hash表使用的方法骂远。
但是ngx_hash_t的實現又有其幾個顯著的特點 :
- ngx_hash_t不像其他的hash表的實現,可以插入刪除元素腰根,它只能一次初始化激才,就構建起整個hash表以后,既不能再刪除额嘿,也不能在插入元素了贸营。
- ngx_hash_t的開鏈并不是真的開了一個鏈表,實際上是開了一段連續(xù)的存儲空間岩睁,幾乎可以看做是一個數組。這是因為ngx_hash_t在初始化的時候揣云,會經歷一次預計算的過程捕儒,提前把每個桶里面會有多少元素放進去給計算出來,這樣就提前知道每個桶的大小了邓夕。那么就不需要使用鏈表刘莹,一段連續(xù)的存儲空間就足夠了。這也從一定程度上節(jié)省了內存的使用焚刚。
從上面的描述点弯,我們可以看出來,這個值越大矿咕,越造成內存的浪費抢肛。就兩步狼钮,首先是初始化,然后就可以在里面進行查找了捡絮。
ngx_hash_wildcard_t
nginx為了處理帶有通配符的域名的匹配問題熬芜,實現了ngx_hash_wildcard_t這樣的hash表。他可以支持兩種類型的帶有通配符的域名福稳。一種是通配符在前的涎拉,另外一種是通配符在末尾的,例如:“mail.xxx.*”的圆,請?zhí)貏e注意通配符在末尾的不像位于開始的通配符可以被省略掉鼓拧。這樣的通配符,可以匹配mail.xxx.com越妈、mail.xxx.com.cn季俩、mail.xxx.net之類的域名。
ngx_hash_combined_t
組合類型hash表叮称,該hash表的定義如下:
<pre>typedef struct {
ngx_hash_t hash;
ngx_hash_wildcard_t *wc_head;
ngx_hash_wildcard_t *wc_tail;
} ngx_hash_combined_t;</pre>
從其定義顯見种玛,該類型實際上包含了三個hash表,一個普通hash表瓤檐,一個包含前向通配符的hash表和一個包含后向通配符的hash表赂韵。
nginx提供該類型的作用,在于提供一個方便的容器包含三個類型的hash表挠蛉,當有包含通配符的和不包含通配符的一組key構建hash表以后祭示,以一種方便的方式來查詢,你不需要再考慮一個key到底是應該到哪個類型的hash表里去查了谴古。
ngx_hash_keys_arrays_t
大家看到在構建一個ngx_hash_wildcard_t的時候质涛,需要對通配符的哪些key進行預處理。這個處理起來比較麻煩掰担。而當有一組key汇陆,這些里面既有無通配符的key,也有包含通配符的key的時候带饱。我們就需要構建三個hash表毡代,一個包含普通的key的hash表,一個包含前向通配符的hash表勺疼,一個包含后向通配符的hash表(或者也可以把這三個hash表組合成一個ngx_hash_combined_t)教寂。在這種情況下,為了讓大家方便的構造這些hash表执庐,nginx提供給了此輔助類型酪耕。
ngx_chain_t
nginx的filter模塊在處理從別的filter模塊或者是handler模塊傳遞過來的數據(實際上就是需要發(fā)送給客戶端的http response)。這個傳遞過來的數據是以一個鏈表的形式(ngx_chain_t)轨淌。而且數據可能被分多次傳遞過來迂烁。也就是多次調用filter的處理函數看尼,以不同的ngx_chain_t。
ngx_buf_t
這個ngx_buf_t就是這個ngx_chain_t鏈表的每個節(jié)點的實際數據婚被。該結構實際上是一種抽象的數據結構狡忙,它代表某種具體的數據。這個數據可能是指向內存中的某個緩沖區(qū)址芯,也可能指向一個文件的某一部分灾茁,也可能是一些純元數據(元數據的作用在于指示這個鏈表的讀取者對讀取的數據進行不同的處理)。
struct ngx_buf_s {
u_char *pos;
u_char *last;
off_t file_pos;
off_t file_last;
u_char *start; /* start of buffer */
u_char *end; /* end of buffer */
ngx_buf_tag_t tag;
ngx_file_t *file;
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;
unsigned flush:1;
unsigned sync:1;
unsigned last_buf:1;
unsigned last_in_chain:1;
unsigned last_shadow:1;
unsigned temp_file:1;
/* STUB */ int num;
};
pos: 當buf所指向的數據在內存里的時候谷炸,pos指向的是這段數據開始的位置北专。
last: 當buf所指向的數據在內存里的時候,last指向的是這段數據結束的位置旬陡。
file_pos: 當buf所指向的數據是在文件里的時候拓颓,file_pos指向的是這段數據的開始位置在文件中的偏移量。
file_last: 當buf所指向的數據是在文件里的時候描孟,file_last指向的是這段數據的結束位置在文件中的偏移量驶睦。
start: 當buf所指向的數據在內存里的時候,這一整塊內存包含的內容可能被包含在多個buf中(比如在某段數據中間插入了其他的數據匿醒,這一塊數據就需要被拆分開)场航。那么這些buf中的start和end都指向這一塊內存的開始地址和結束地址。而pos和last指向本buf所實際包含的數據的開始和結尾廉羔。
end: 解釋參見start溉痢。
tag: 實際上是一個void*類型的指針,使用者可以關聯任意的對象上去憋他,只要對使用者有意義孩饼。
file: 當buf所包含的內容在文件中時,file字段指向對應的文件對象竹挡。
shadow: 當這個buf完整copy了另外一個buf的所有字段的時候镀娶,那么這兩個buf指向的實際上是同一塊內存,或者是同一個文件的同一部分揪罕,此時這兩個buf的shadow字段都是指向對方的梯码。那么對于這樣的兩個buf,在釋放的時候耸序,就需要使用者特別小心,具體是由哪里釋放鲁猩,要提前考慮好坎怪,如果造成資源的多次釋放,可能會造成程序崩潰廓握!
temporary: 為1時表示該buf所包含的內容是在一個用戶創(chuàng)建的內存塊中搅窿,并且可以被在filter處理的過程中進行變更嘁酿,而不會造成問題。
memory: 為1時表示該buf所包含的內容是在內存中男应,但是這些內容卻不能被進行處理的filter進行變更闹司。
mmap: 為1時表示該buf所包含的內容是在內存中, 是通過mmap使用內存映射從文件中映射到內存中的,這些內容卻不能被進行處理的filter進行變更沐飘。
recycled: 可以回收的游桩。也就是這個buf是可以被釋放的。這個字段通常是配合shadow字段一起使用的耐朴,對于使用ngx_create_temp_buf 函數創(chuàng)建的buf借卧,并且是另外一個buf的shadow,那么可以使用這個字段來標示這個buf是可以被釋放的筛峭。
in_file: 為1時表示該buf所包含的內容是在文件中铐刘。
flush: 遇到有flush字段被設置為1的的buf的chain,則該chain的數據即便不是最后結束的數據(last_buf被設置影晓,標志所有要輸出的內容都完了)镰吵,也會進行輸出,不會受postpone_output配置的限制挂签,但是會受到發(fā)送速率等其他條件的限制疤祭。
sync:
last_buf: 數據被以多個chain傳遞給了過濾器,此字段為1表明這是最后一個buf竹握。
last_in_chain: 在當前的chain里面画株,此buf是最后一個。特別要注意的是last_in_chain的buf不一定是last_buf啦辐,但是last_buf的buf一定是last_in_chain的谓传。這是因為數據會被以多個chain傳遞給某個filter模塊。
last_shadow: 在創(chuàng)建一個buf的shadow的時候芹关,通常將新創(chuàng)建的一個buf的last_shadow置為1续挟。
temp_file: 由于受到內存使用的限制,有時候一些buf的內容需要被寫到磁盤上的臨時文件中去侥衬,那么這時诗祸,就設置此標志 。
ngx_list_t
ngx_list_t顧名思義轴总,看起來好像是一個list的數據結構直颅。這樣的說法,算對也不算對怀樟。因為它符合list類型數據結構的一些特點功偿,比如可以添加元素,實現自增長往堡,不會像數組類型的數據結構械荷,受到初始設定的數組容量的限制共耍,并且它跟我們常見的list型數據結構也是一樣的,內部實現使用了一個鏈表吨瞎。
那么它跟我們常見的鏈表實現的list有什么不同呢痹兜?不同點就在于它的節(jié)點,它的節(jié)點不像我們常見的list的節(jié)點颤诀,只能存放一個元素字旭,ngx_list_t的節(jié)點實際上是一個固定大小的數組。
ngx_queue_t
ngx_queue_t是nginx中的雙向鏈表着绊,在nginx源碼目錄src/core下面的ngx_queue.h|c里面谐算。它的原型如下:
typedef struct ngx_queue_s ngx_queue_t;
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
nginx的配置系統(tǒng)
nginx的配置系統(tǒng)由一個主配置文件和其他一些輔助的配置文件構成。這些配置文件均是純文本文件归露,全部位于nginx安裝目錄下的conf目錄下洲脂。
配置文件中以#開始的行,或者是前面有若干空格或者TAB剧包,然后再跟#的行恐锦,都被認為是注釋,也就是只對編輯查看文件的用戶有意義疆液,程序在讀取這些注釋行的時候一铅,其實際的內容是被忽略的。
由于除主配置文件nginx.conf以外的文件都是在某些情況下才使用的堕油,而只有主配置文件是在任何情況下都被使用的潘飘。
在nginx.conf中,包含若干配置項掉缺。每個配置項由配置指令和指令參數 2個部分構成卜录。指令參數也就是配置指令對應的配置值。
指令概述
配置指令是一個字符串眶明,可以用單引號或者雙引號括起來艰毒,也可以不括。但是如果配置指令包含空格搜囱,一定要引起來丑瞧。
指令參數
指令的參數使用一個或者多個空格或者TAB字符與指令分開。指令的參數有一個或者多個TOKEN串組成蜀肘。TOKEN串之間由空格或者TAB鍵分隔绊汹。
TOKEN串分為簡單字符串或者是復合配置塊。復合配置塊即是由大括號括起來的一堆內容扮宠。一個復合配置塊中可能包含若干其他的配置指令西乖。如果一個配置指令的參數全部由簡單字符串構成,也就是不包含復合配置塊,那么我們就說這個配置指令是一個簡單配置項浴栽,否則稱之為復雜配置項。
例如下面這個是一個簡單配置項:
error_page 500 502 503 504 /50x.html;
對于簡單配置轿偎,配置項的結尾使用分號結束典鸡。對于復雜配置項,包含多個TOKEN串的坏晦,一般都是簡單TOKEN串放在前面萝玷,復合配置塊一般位于最后,而且其結尾昆婿,并不需要再添加分號球碉。例如下面這個復雜配置項:
location / {
root /home/jizhao/nginx-book/build/html;
index index.html index.htm;
}