从$ request_body记录POST数据


71

我的配置设置可以处理一堆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;
}

冰壶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。非常感谢朝着正确方向的任何帮助!谢谢!

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

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找到了可行的解决方案。希望这可以帮助其他人。


你有什么办法吗?我正面临着类似的问题。
James C

而不是set $test 0;尝试return 200;从虚拟位置进行操作,对我来说,它然后返回了预期的200,并且我的身体仍然记录下来。
Elven Spellmaker

Answers:


83

此解决方案就像一个咒语一样工作(于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脚本。


11
我必须移动“ log_format postdata $ request_body;”;到服务器部分,因为nginx说“这里不允许使用log_format指令”
Oleg Neumyvakin

6
这是正确的答案。除了像@OlegNeumyvakin提到的那样,我不得不移动这log_format部分。但就我而言,我必须将其移动到“ http”块内,而不是“ server”块内,才能正常工作。但这确实成功了!
马特

1
@OlegNeumyvakin&Matt:我已经将您的评论纳入了答案(目前正在等待审核)。谢谢!
格雷格·杜比奇

我什至不得不将log_format线移到服务器部分上方。但后来效果很好。(nginx / 1.9.3)
TheFisch '16

1
是的,仅在nginx配置的http部分中允许使用log_format。我相应地更改了示例。
ahofmann

39

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

3
这比公认的答案更好,因为它不需要安装fastcgi
Fluffy 2014年

6
安装者apt-get install nginx-full
firelynx

4
@ user4我只能在日志中看到破折号。有什么问题?我使用echo_read_request_body。和回声模块已安装
Vladimir Kovalchuk

对我来说,如果我重定向(例如301/302),它就会request_body消失
deceleratedcaviar

@dcousens您在什么时候为301/302服务?如果您要在nginx location指令中直接设置301/302重定向,那么您看到的行为就很有意义。如果它是在经过一些php处理之后发生的,那将有些奇怪。您应该开始一个新的堆栈溢出问题,以便有人可以帮助您。
Dale Anderson

12

好。因此,最终我能够记录发布数据并返回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时写入了相同的日志。绝对不是最优雅的解决方案,我欢迎任何更好的解决方案。我已经看过post模块,但是在我的场景中,我无法从源代码重新编译。


1
您想出的解决方案与此处接受的答案非常相似:stackoverflow.com/questions/17609472 / ...由于nginx不会解析正文,除非将其发送到代理或快速cgi服务器,所以对自身进行代理即可。
turtlemonvh

我们使用类似的解决方案,通过proxy_pass POST请求到另一个位置。
arganzheng '16

7

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

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

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

5

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


0

我有一个类似的问题。GET请求有效,并且其(空)请求正文已写入日志文件。POST请求失败并显示404。尝试了一下,我发现所有POST请求都失败了。我找到了一个论坛帖子,询问有关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的价值有关。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.