コンテンツにスキップ

ボディを書き換える

ボディフィルタは、nginxがレスポンスを送る間に動きます。レスポンスを作ったのがどのハンドラでも、upstreamでも同じです。mruby_output_body_filterを使うと、RubyのスクリプトはNginx::Filter#bodyでボディを読み、Nginx::Filter#body=でボディを置き換えます。ヘッダフィルタのmruby_output_header_filterはその前に動き、レスポンスのヘッダを変えられます。

このlocationは、ディスクにあるテキストファイルを送ります。ヘッダフィルタはContent-Typeをtext/htmlにし、ボディフィルタは&、<、>をエスケープして、テキストをHTMLのページで包みます。

test/conf/conf.d/76-guide-body-filter.conf
server {
listen 18167;
# A text file from disk, sent as an HTML page.
location = /notes {
alias html/guide_notes.txt;
mruby_output_header_filter_code 'Nginx::Request.new.content_type = "text/html"';
mruby_output_body_filter build/nginx/html/guide_body_filter.rb;
}
}
test/html/guide_body_filter.rb
f = Nginx::Filter.new
text = f.body.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
f.body = "<!doctype html>\n<title>notes</title>\n<pre>\n#{text}</pre>\n"
test/html/guide_body_filter.request:ケースが送るリクエスト
GET /notes HTTP/1.1
Host: 127.0.0.1:18167
Connection: close
test/html/guide_body_filter.response:ケースが比べるレスポンス
HTTP/1.1 200 OK
Content-Type: text/html
<!doctype html>
<title>notes</title>
<pre>
Notes from disk.
The filter escapes &lt;b&gt; and &amp;.
</pre>

CIが動くたびに、ケースのtest/t/cases/guides.rbがこのリクエストを送ります。ケースは、ステータス行、ここに載せたヘッダ、ボディ全体を比べます。5個のファイルを最後に変えたのは、2026-10-29のコミット32219e53です。

  • ボディフィルタは、ディスクのファイルのような長さの分かるレスポンスを、1つのバッファとして読みます。Content-Lengthの無いレスポンスは、フィルタが読まないまま、nginxが先へ渡します。詳しくはNginx::Filterにあります。
  • ngx_mrubyは、新しいボディの長さをContent-Lengthに入れて送ります。
  • ユースケースのMarkdownをHTMLに変換する出力フィルタは、同じ場所で、gemのmruby-discountを使ってMarkdownを変換します。