介紹
當(dāng)在location區(qū)塊中使用 if 指令的時(shí)候會(huì)有一些問題, 在某些情況下它并不按照你的預(yù)期運(yùn)行而是做一些完全不同的事情. 而在另一些情況下他甚至?xí)霈F(xiàn)段錯(cuò)誤. 一般來說避免使用 if 指令是個(gè)好主意谜慌。
在 location 區(qū)塊里if指令下唯一100%安全的指令應(yīng)該只有:
return …;
rewrite … last;
除此以外的指令都可能導(dǎo)致不可預(yù)期的行為, 包括詭異的發(fā)出段錯(cuò)誤信號(hào)(SIGSEGV)已慢。
要著重注意的是if的行為不是反復(fù)無常的, 給出兩個(gè)條件完全一致的請(qǐng)求, Nginx并不會(huì)出現(xiàn)一個(gè)正常工作而一個(gè)請(qǐng)求失敗的隨機(jī)情況, 在明晰的測試和理解下 if 是完全可用的. 盡管如此, 在這里還是建議使用其他指令。
總有一些情況你無法避免去使用 if 指令, 比如你需要測試一個(gè)變量, 而它沒有相應(yīng)的配置指令禾蚕。
if ($request_method = POST) {
return 405;
}
if ($args ~ post=140){
rewrite ^ http://example.com/ permanent;
}
如何替換掉if
使用 try_files 如果他適合你的需求. 在其他的情況下使用 “return …” 或者 “rewrite … last”. 還有一些情況可能要把 if 移動(dòng)到 server 區(qū)塊下(只有當(dāng)其他的rewrite模塊指令也允許放在的地方才是安全的)。
如下可以安全地改變用于處理請(qǐng)求的 location。
location / {
error_page 418 = @other;
recursive_error_pages on;
if ($something) {
return 418;
}
# some configuration
...
}
location @other {
# some other configuration
...
}
在某些情況下使用嵌入腳本模塊(嵌入perl或者其他一些第三方模塊)處理這些腳本更佳劳澄。
例子
以下是一些例子用來解釋為什么if是邪惡的. 非專業(yè)人事指, 請(qǐng)勿模仿!
# 這里收集了一些出人意料的坑爹配置來展示 location 中的 if 指令是萬惡的
# 只有第二個(gè) header 才會(huì)在響應(yīng)中展示
# 這不是Bug, 只是他的處理流程如此
location /only-one-if {
set $true 1;
if ($true) {
add_header X-First 1;
}
if ($true) {
add_header X-Second 2;
}
return 204;
}
# 因?yàn)閕f, 請(qǐng)求會(huì)在未改變uri的情況下下發(fā)送到后臺(tái)的 '/'
location /proxy-pass-uri {
proxy_pass http://127.0.0.1:8080/;
set $true 1;
if ($true) {
# nothing
}
}
# 因?yàn)閕f, try_files 失效
location /if-try-files {
try_files /file @fallback;
set $true 1;
if ($true) {
# nothing
}
}
# nginx 將會(huì)發(fā)出段錯(cuò)誤信號(hào)(SIGSEGV)
location /crash {
set $true 1;
if ($true) {
# fastcgi_pass here
fastcgi_pass 127.0.0.1:9000;
}
if ($true) {
# no handler here
}
}
# alias with captures isn't correcly inherited into implicit nested location created by if
# alias with captures 不能正確的繼承到由if創(chuàng)建的隱式嵌入的location
location ~* ^/if-and-alias/(?<file>.*) {
alias /tmp/$file;
set $true 1;
if ($true) {
# nothing
}
}
為什么會(huì)這樣且到現(xiàn)在都沒修復(fù)這些問題?
if 指令是 rewrite 模塊中的一部分, 是實(shí)時(shí)生效的指令.另一方面來說, nginx 配置大體上是陳述式的.在某些時(shí)候用戶出于特殊是需求的嘗試, 會(huì)在if里寫入一些非rewrite指令, 這直接導(dǎo)致了我們現(xiàn)處的情況. 大多數(shù)情況下他可以工作, 但是…看看上面。
看起來唯一正確的修復(fù)方式是完全禁用if中的非rewrite指令. 但是這將破壞很多現(xiàn)有可用的配置, 所以還沒有修復(fù)逝撬。
如果你還是想知道該如何使用if
如果你看完了上面所有內(nèi)容還是想使用 if:
請(qǐng)確認(rèn)你確實(shí)理解了該怎么用它.一些比較基本的用法可以在這里找到
做適當(dāng)?shù)臏y試
我已經(jīng)警告過你了!
文章翻譯自源: http://wiki.nginx.org/IfIsEvil
原文鏈接:Nginx配置陷阱之萬惡的if指令