ngx_mrubyを使ってNginxを制御するときに、 mruby_set
と if
を使うことが多いと思います。
例えばiPhoneからのアクセスの場合のみ特定の処理をしたいとします。 その場合以下の様なコード(nginx.conf)になると思います。
mruby_set_code $is_iphone ' hin = Nginx::Headers_in.new # 判定分が雑だけど例題なのでご容赦・・・ /iPhone/ === hin['User-Agent'] '; if($is_iphone) { # iPhoneの時だけ行なう処理 }
User-Agent
に iPhone
という文字列が含まれていれば true
を返し、そうでなければ false
を返却し、その結果を $is_iphone
変数に格納します。
そして、この変数が真の時だけ特定の処理を行います。
これは意図した動作を行なうのでしょうか?
一見問題なさそうに見えますが、 これは意図した動作をしません。 なぜなら、 iPhone以外のアクセスの時($is_iphoneがfalseの時)もif分の中の処理を実行してしまいます。
これはなぜかというと、 ngx_mrubyが*1最終値をStringに変換してNginxの変数に格納しているのです。
つまり $is_iphone
にはtrueまたはfalseという文字列が格納されています。
Nginxにおける if
は、空文字または0の場合は偽として処理されますが、それ以外は真として処理されます。
a variable name; false if the value of a variable is an empty string or “0”; http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if
よって、意図した動作をさせるためにはif分を以下のように書き換えます。
if($is_iphone = ture) { # iPhoneの時だけ行なう処理 }
これで期待する動作を行うようになりました!
2016/08/01追記
id:matsumoto_r さんによって、Nginx::TRUE
と Nginx::FALSE
という定数が追加されました!
この定数を使って、以下のように書きなおすことができ、if
ディレクティブで特別意識する必要がなくなりました!
mruby_set_code $is_iphone ' hin = Nginx::Headers_in.new /iPhone/ === hin['User-Agent'] ? Nginx::TRUE : Nginx::FALSE '; if($is_iphone) { # iPhoneの時だけ行なう処理 }
*1:ngx_mrubyがやっているのだろうと思ってソースを読んだのですが確信はないです。。間違っているかも。。