nginxのerror_pageとluaでerror_page内でステータスの変更・処理を行う
error_pageを指定しているはずなのに、期待したページが表示されなかったことがあったのでメモ。
やりたいことは以下です。
①404エラー時にステータスコードを502エラーとしてカスタムしたエラーページ(50x.html)を返す
②error_pageの中では条件によっては200を返す
環境としては、openrestyを利用してnginxとluaを使う感じです。
まずは①を試します。
通常は、error_pageの箇所に=502を記述し、リダイレクト先を/50x.htmlとすれば済みますが、最終的にlocationの中でいろいろやりたいので以下のように書いて試しました。
↓nginx.confの抜粋
error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } error_page 404 /404.html; location = /404.html { return 502; }
この場合、curlでリクエストを投げるとopenrestyとバージョンが表示されたデフォルトっぽい自動で生成されたエラーページが表示されました。
(error_pageを書いてない場合、以下のフォーマットのページがデフォルトで表示されるのかな?)
↓curlとレスポンス
curl http://localhost:80/abc -w '%{http_code}\n' -s <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>openresty/1.13.6.2</center> </body> </html> 404
ログを見ても/404.htmlにもアクセスしておらず、return 502でステータスコードが変わるわけでもなくダメダメの模様。(ちなみにreturn 502を消すと/404.htmlまではアクセスされた)
↓ログ
2019/05/03 15:27:55 [error] 141#141: *18 open() "/usr/local/openresty/nginx/html/abc" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "GET /abc HTTP/1.1", host: "localhost"
これが動かなかった理由ですが、まずrecursive_error_pagesをONとしていなかったのが原因。
recursive_error_pagesはデフォルトでOFFになっており、error_page内で再度エラーとしてもハンドリングされないみたい。
以下のようにrecursive_error_pagesをONにしてやり、上位の404で処理するlocation内で、再度error_page404の記述をしてやれば動きました。
(下記の例のlocationはまったぐ意味がないが再帰的なerror_pageが動くということを示すためのもの。)
↓修正版
error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # ここに定義が必要 recursive_error_pages on; error_page 404 /404.html; location = /404.html { error_page 404 =502 /50x.html; }
結果カスタムしたエラーページが返ってきてレスポンスコードも書き換わっている。
↓curlとレスポンス
curl http://localhost:80/abc -w '%{http_code}\n' -s <!DOCTYPE html> <html> <head> <title>Error</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>An error occurred.</h1> <p>Sorry, the page you are looking for is currently unavailable.<br/> Please try again later.</p> <p>If you are the system administrator of this resource then you should check the <a href="http://nginx.org/r/error_log">error log</a> for details.</p> <p><em>Faithfully yours, OpenResty.</em></p> </body> </html> 502
これに加えてluaも利用したうえで記事の先頭の方で書いた①と②を実現する処理を書いてみる。
↓luaのコードを加えたnginx.conf
location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # これをONにすることでluaでexit(502)とした際も上記のerror_pageで処理される recursive_error_pages on; error_page 404 @myError; location @myError { content_by_lua_block { if ngx.var.arg_flg == "1" then ngx.status = 200; -- execだけではstatusは書き換わらない ngx.exec("/"); else return ngx.exit(502); end } # 404に対してerror_pageを書きたいときはここに記述 #error_page 404 /50x.html; }
flg=1とした場合
↓curlとレスポンス
curl "http://localhost:80/abc?flg=1" -w '%{http_code}\n' -s <!DOCTYPE html> <html> <head> <title>Welcome to OpenResty!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to OpenResty!</h1> <p>If you see this page, the OpenResty web platform is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="https://openresty.org/">openresty.org</a>.<br/> Commercial support is available at <a href="https://openresty.com/">openresty.com</a>.</p> <p><em>Thank you for flying OpenResty.</em></p> </body> </html> 200
flg=2とした場合
↓curlとレスポンス
curl "http://localhost:80/abc?flg=2" -w '%{http_code}\n' -s <!DOCTYPE html> <html> <head> <title>Error</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>An error occurred.</h1> <p>Sorry, the page you are looking for is currently unavailable.<br/> Please try again later.</p> <p>If you are the system administrator of this resource then you should check the <a href="http://nginx.org/r/error_log">error log</a> for details.</p> <p><em>Faithfully yours, OpenResty.</em></p> </body> </html> 404
意図したとおり、luaを利用してのerror_page内で条件によるステータスの変更、error_pageでも自動生成されるエラーページでなく、用意したエラーページが表示されることが確認できました!キモはrecursive_error_pages をONにすることでした。
また、error_pageをlocation内に再定義することで再帰的にerror_pageの処理もできるみたいですね。
以上