web-dev-qa-db-ja.com

$ request_bodyからのPOSTデータのロギング

分析を処理し、ロギング用のクエリ文字列を解析するのに適切に機能するピクセルをレンダリングするGETリクエストの束を処理するための設定があります。追加のサードパーティデータストリームを使用して、要求本文内に予想されるログ可能な形式のJSONがある特定のURLへのPOST要求を処理する必要があります。セカンダリサーバーをproxy_passで使用したくないので、GETリクエストで行うように、応答全体を関連するログファイルに記録したいだけです。私が使用しているいくつかのコードのスニペットは次のようになります。

GETリクエスト(これはうまく機能します):

location ^~ /rl.gif {
  set $rl_lcid $arg_lcid;
  if ($http_cookie ~* "lcid=(.*\S)")
  {
    set $rl_lcid $cookie_lcid;
  }
  empty_gif;
  log_format my_tracking '{ "guid" : "$rl_lcid", "data" : "$arg__rlcdnsegs" }';
  access_log  /mnt/logs/nginx/my.access.log my_tracking;
  rewrite ^(.*)$ http://my/url?id=$cookie_lcid? redirect;
}

これが私がやろうとしていることです:POSTリクエスト(これは機能しません):

location /bk {
  log_format bk_tracking $request_body;
  access_log  /mnt/logs/nginx/bk.access.log bk_tracking;
}

カーリングcurl http://myurl/bk -d name=exampleにより、404ページが見つかりません。

それから私は試しました:

location /bk.gif {
  empty_gif;
  log_format bk_tracking $request_body;
  access_log  /mnt/logs/nginx/bk.access.log bk_tracking;
}

カーリングcurl http://myurl/bk.gif -d name=exampleは、私に405 Not Allowedを与えます。

私の現在のバージョンはnginx/0.7.62です。正しい方向への助けは大歓迎です!ありがとう!

UPDATEこれで、私の投稿は次のようになります。

location /bk {
  if ($request_method != POST) {
    return 405;
  }
  proxy_pass $scheme://127.0.0.1:$server_port/dummy;
  log_format my_tracking $request_body;
  access_log  /mnt/logs/nginx/my.access.log my_tracking;
}
location /dummy { set $test 0; }

投稿データを正しく記録していますが、リクエスター側で404を返します。上記のコードを変更して200を返す場合:

location /bk {
  if ($request_method != POST) {
    return 405;
  }
  proxy_pass $scheme://127.0.0.1:$server_port/dummy;
  log_format my_tracking $request_body;
  access_log  /mnt/logs/nginx/my.access.log my_tracking;
  return 200;
}
location /dummy { set $test 0; }

次に、200を正しく返しますが、投稿データを記録しなくなります。

ANOTHER UPDATE Kindaは有効なソリューションを見つけました。これが他の人の助けになることを願っています。

58
Chris Barretto

このソリューションはチャームのように機能します(log_formatがnginx構成のhttp部分にある必要があることを尊重するために2017年に更新されました):

log_format postdata $request_body;

server {
    # (...)

    location = /post.php {
       access_log  /var/log/nginx/postdata.log  postdata;
       fastcgi_pass php_cgi;
    }
}

トリックは、nginxにcgiスクリプトを呼び出すと信じさせることだと思います。

66
ahofmann

Echo_read_request_bodyを試してください。

" echo_read_request_body ...リクエストボディを明示的に読み取り、$ request_body変数が常に空でない値を持つようにします(ボディが大きすぎてNginxによってローカル一時ファイルに保存されていない場合)。 」

location /log {
  log_format postdata $request_body;
  access_log /mnt/logs/nginx/my_tracking.access.log postdata;
  echo_read_request_body;
}
35
boqapt

OK。最終的に、投稿データをログに記録して200を返すことができました。基本的にerror_pageの自然な動作をオーバーライドすることは誇りに思っていませんが、nginxとタイムラインの経験不足がこのソリューションにつながっています。 :

location /bk {
  if ($request_method != POST) {
    return 405;
  }
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $Host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_redirect off;
  proxy_pass $scheme://127.0.0.1:$server_port/success;
  log_format my_tracking $request_body;
  access_log  /mnt/logs/nginx/my_tracking.access.log my_tracking;
}
location /success {
  return 200;
}
error_page   500 502 503 504  /50x.html;
location = /50x.html {
  root   /var/www/nginx-default;
  log_format my_tracking $request_body;
  access_log  /mnt/logs/nginx/my_tracking.access.log my_tracking_2;
}

その構成によれば、プロキシパスは常に200を返すように見えます。 500を取得することもありますが、error_logを投げて何が起こっているのかを確認したときに、request_bodyデータがすべてそこにあり、問題を見つけることができませんでした。だから私はそれを捕まえて、同じログに書き込みました。 nginxはトラッキング変数の同じ名前を好まないので、my_tracking_2を使用し、200を返すときと同じログに書き込みました。間違いなく最もエレガントなソリューションではなく、より良いソリューションを歓迎します。投稿モジュールを見てきましたが、私のシナリオでは、ソースから再コンパイルできませんでした。

11
Chris Barretto

FWIW、この設定は私のために働いた:

location = /logpush.html {
  if ($request_method = POST) {
    access_log /var/log/nginx/Push.log Push_requests;
    proxy_pass $scheme://127.0.0.1/logsink;
    break;
  }   
  return 200 $scheme://$Host/serviceup.html;
}   
#
location /logsink {
  return 200;
}
6
user2096933

nginxログ形式はここから取得します: http://nginx.org/en/docs/http/ngx_http_log_module.html

追加のものをインストールする必要はありません

GETおよびPOSTリクエストで私のために働いた:

upstream my_upstream {
   server upstream_ip:upstream_port;
}

location / {
    log_format postdata '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" "$request_body"';
    access_log /path/to/nginx_access.log postdata;
    proxy_set_header Host $http_Host;
    proxy_pass http://my_upstream;
    }
}

upstream_ipupstream_portを変更するだけです

4
NoamG

同様の問題がありました。 GET要求は機能し、その(空の)要求本文はログファイルに書き込まれました。 POSTリクエストは404で失敗しました。少し実験してみると、allPOSTリクエストが失敗していることがわかりました。 POSTリクエストについて質問するフォーラム投稿 が見つかり、そこでの解決策が私にとってはうまくいきました。その解決策は?以下の例のように、proxy_header行の直前にproxy_pass行を追加します。

server {
    listen       192.168.0.1:45080;
    server_name  foo.example.org;

    access_log  /path/to/log/nginx/post_bodies.log post_bodies;
    location / {
      ### add the following proxy_header line to get POSTs to work
      proxy_set_header Host $http_Host;
      proxy_pass   http://10.1.2.3;
    }
}

(これはnginx 1.2.1で価値があります。)

0
epicsmile

以下のソリューションは、私が見つけた最適な形式でした。

log_format postdata escape=json '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" "$request_body"';
server {
        listen 80;

        server_name api.some.com;

        location / {
         access_log  /var/log/nginx/postdata.log  postdata;
         proxy_pass      http://127.0.0.1:8080;
        }

}

この入力について

curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://api.deprod.com/postEndpoint

その素晴らしい結果を生み出す

201.23.89.149 -  [22/Aug/2019:15:58:40 +0000] "POST /postEndpoint HTTP/1.1" 200 265 "" "curl/7.64.0" "{\"key1\":\"value1\", \"key2\":\"value2\"}"
0
Bruno