この記事は、公式サイトのIf is Evilを抜粋した簡易的な記事です。詳しい内容が必要でしたら、公式サイトのIf is Evilをご覧ください。
はじめに
nginxでは、if文が利用できます。たとえば、Optionsリクエストを捌くときに使います。
location /xxx {
if ($request_method = OPTIONS ) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "origin, authorization, accept";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 200;
}
}
ところが、一般的なプログラミング言語と違い、nginxのlocationにおいて、if文は非常に特殊な動きをします。
特殊な動き
公式サイトのIf is Evilというページに記載があるとおり、「Ifは邪悪」であることが公式に提唱されています。
いくつか抜粋して紹介します。
期待しないヘッダの動作
location /only-one-if {
set $true 1;
if ($true) {
add_header X-First 1;
}
if ($true) {
add_header X-Second 2;
}
return 204;
}
このコードを実行(アクセス)すると、X-Second 2
のヘッダしか送られてきていないことがわかります。これは、多くの人が想像する一般的なプログラミング言語の動きとは大きく異なります。
一般的なプログラミング言語としての動きで考えると、X-FirstからX-Thirdまでの全てのヘッダが書き込まれることを期待してしまいますが、nginxにおいてはそうではありません。
クラッシュを引き起こすコード
location /crash {
set $true 1;
if ($true) {
# fastcgi_pass here
fastcgi_pass 127.0.0.1:9000;
}
if ($true) {
# no handler here
}
}
このコードを記述すると、SIGSEGVを吐いてnginxがクラッシュします。
なぜ邪悪か
上述したように、多くのプログラマ(あるいは、エンジニア)にとって、nginxのif文の動きは、一般的な感覚とかけ離れています。
これはコードで誤解を与える可能性が格段に大きいことを意味しており、高い確率で好ましくない結果を呼びます。
代替案
公式で綴られている内容によると、try_files
、return ...
、rewrite ... last
などを利用できるようです。
locationディレクティブ以外での挙動
例えば、以下に挙げられているように、serverレベルにifを移動させることは、この場合安全であるようです。
it’s also possible to move ifs to server level (where it’s safe as only other rewrite module directives are allowed within it).
ifsをサーバレベルに移動することも可能です(他のリライトモジュールディレクティブのみが許可されているので安全です)。
まとめ
このように、nginxのlocationディレクティブでは、ifは非常に特殊な動きをします。それを記述しなければならない強い理由がないのであれば、使わないほうが良いでしょう。
nginxの内部動作について詳しく、記述の内容と動作を正しく理解できる場合は使っても構わない、とされていますが、引き継ぎなどで誰かがそのコードに少しでも触れる可能性がある場合は、別の手段を講じることをお勧めします。
軽く触れる程度になってしまいましたが、nginxでlocationディレクティブのif記述の危険性について触れている日本語のサイトがあまり無かったので作成しました。
興味がおありでしたら、紹介した公式ページをgoogle翻訳などを利用して読んでみることをお勧めします。