记录来自$ request_body的POST数据

时间:2011-02-08 22:44:24

标签: logging nginx http-post

我的配置设置可以处理一堆GET请求,这些请求可以呈现处理分析和解析查询字符串以进行日志记录的像素。使用额外的第三方数据流,我需要处理对给定URL的POST请求,该URL在其请求主体内部具有预期可记录格式的JSON。我不想使用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;
}

Curling 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;
}

Curling curl http://myurl/bk.gif -d name=example给了我一个405 Not Allowed

我当前的版本是nginx/0.7.62。非常感谢任何正确方向的帮助!谢谢!

更新 所以现在我的帖子看起来像这样:

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,但不再记录帖子数据。

另一个更新 Kinda找到了一个有效的解决方案希望这可以帮助其他人。

7 个答案:

答案 0 :(得分:65)

这个解决方案就像一个魅力(2017年更新,以表示log_format需要在nginx配置的http部分):

log_format postdata $request_body;

server {
    # (...)

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

我认为诀窍是让nginx相信你会调用一个cgi脚本。

答案 1 :(得分:34)

尝试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;
}

答案 2 :(得分:11)

确定。所以最后我能够记录帖子数据并返回200.这是一种hacky解决方案,我不会为此感到骄傲,这基本上会覆盖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但是当我扔错误日志看看发生了什么时,我的所有request_body数据都在那里,我看不出问题。所以我抓住了它并写入了同一个日志。由于nginx不喜欢跟踪变量的相同名称,我只是使用my_tracking_2并写入与返回200时相同的日志。绝对不是最优雅的解决方案,我欢迎任何更好的解决方案。我见过post模块,但在我的场景中,我无法从源代码重新编译。

答案 3 :(得分:6)

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;
}

答案 4 :(得分:4)

从此处获取

nginx日志格式:http://nginx.org/en/docs/http/ngx_http_log_module.html

无需再安装任何其他内容

为我GETPOST次请求工作:

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

即可

答案 5 :(得分:1)

以下解决方案是我找到的最佳格式。

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\"}"

答案 6 :(得分:0)

我有类似的问题。 GET请求工作,其(空)请求主体被写入日志文件。 POST请求因404失败。试验一下,我发现所有 POST请求都失败了。我找到了forum posting asking about POST requests,解决方案对我有用。那解决方案?在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的价值所在。)