少しはまった。正規表現の設定のほうが後で評価されて、設定が上書きされるのか。そういえば、apacheもそうだったかな?
例
URL: /fooにaliasを設定しているとする。で、/foo以外の画像(正規表現で指定)へのリクエストはreverse proxyしたいとする(/foo/bar.jpgはreverse proxyさせずにaliasで設定しているdirectoryから配信したい)。
この場合、/fooの設定は"location /foo"ではなくて、"location ^~ /foo"じゃないとダメ。
###### 設定A # location /foo { # 間違い location ^~ /foo { alias /path/to/foo; index index.html index.htm; } ###### 設定B location ~ .+\.(jpg|gif|png)$ { proxy http://image.example.com/; }
"location /foo"だと"/foo/bar.jpg"のリクエストに対して、その後の設定Bの正規表現のlocationで上書きされて、reverse proxy先のサーバから応答が返ってきた。
おや?と思ったのでnginxのwikiを読むと、locationを読む順番は
- リテラル文字列(not 正規表現)のlocation
- 正規表現のlocation
- ~* : case insensitive matching
- ~ : case sensitive matching
となっていた。じゃあ、なぜ"location /foo"ではダメで、"location ^~ /foo"だとOKなのか。
2種類のprefix
locationが反映される順番を変更できる2つのprefix。
"location = /path"
指定した文字列と完全一致するリクエストが適用される。マッチすれば、その後の正規表現はチェックされない。なので、wikiに
For example, if the request "/" occurs frequently, then using "location = /" will expedite the processing of this request.
こう記述されてるように、"/"へのアクセスは"location = /"が適用されて終了するので、頻繁に"/"にリクエストが来るなら、これを設定したほうがパフォーマンス上がるよっていうこと。
"location ^~ /path"
指定した文字列と前方一致するリクエストが適用される。マッチすれば、その後の正規表現はチェックされない。上に書いた例ではこれを使ったので、"/foo/bar.jpg"へのリクエストは設定Aが適用されてそこで終わり。reverse proxyには行かない。
wikiにまとめが書いていた。
1. Directives with the = prefix that match the query exactly. If found, searching stops.
2. All remaining directives with conventional strings. If this match used the ^~ prefix, searching stops.
3. Regular expressions, in the order they are defined in the configuration file.
4. If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
apacheの例
apacheでも
Alias /foo /path/to/foo <Location /foo> # 設定A </Location> <LocationMatch .+\.(jpg|png|gif)$> # 設定B </LocationMatch>
と書いた場合、/foo/bar.jpgへのリクエストには設定Bが適用される。はず。
追記
apacheの場合はLocationとLocationMatch自体には優先順位はなくて、後から書いた設定が上書きをするだけだった。