可以使用nginx location指令发送http请求吗?

时间:2018-12-30 04:27:47

标签: http nginx curl measurement-protocol

也许这是微不足道的,但是我没有发现任何有意义的东西,或者我不知道在哪里看...

(如何)一旦请求特定路径就可以发送curl /任何命令?

遵循这些原则,但实际上会起作用:

location / {
curl --data 'v=1&t=pageview&tid=UA-XXXXXXXX-X&cid=123&dp=hit'  https://google-analytics.com/collect
}

4 个答案:

答案 0 :(得分:3)

(如评论中所指出),ngx_http_lua_module可以做到!

location / {
          access_by_lua_block  {
            os.execute("/usr/bin/curl --data 'v=1&t=pageview&tid=UA-XXXXXXXX-X&cid=123&dp=hit'  https://google-analytics.com/collect >/dev/null 2>/dev/null") 
        }
}

请注意,执行将暂停页面加载,直到卷曲完成为止。要在后台运行curl并立即继续页面加载,请在末尾添加一个空格和一个&,使它看起来像

>/dev/null 2>/dev/null &")

答案 1 :(得分:3)

您要执行的操作-针对服务器上的每个URL请求为Google Analytics(分析)执行新的curl实例-解决该问题的方法错误:

  1. Nginx本身可以轻松地在任何给定时间为10k +并发连接提供服务,作为下限(即,如果您做正确的话,至少是最低要求),请参阅https://en.wikipedia.org/wiki/C10k_problem

    li>
  2. 另一方面,fork(创建新进程的基础system call)的性能,如果要为每个请求运行curl,这是必要的,它非常慢,以每秒1k的分叉为上限,例如,如果您做对了,那将是有史以来最快的速度,请参阅Faster forking of large processes on Linux?


具有更好架构的最佳替代解决方案是什么?

  • 我的建议是通过批处理执行此操作。通过实时执行Google Analytics(分析)并不能真正获得任何收益,延迟5分钟的统计数据就足够了。您可以使用自己选择的编程语言编写一个简单的脚本,以浏览相关的http://nginx.org/r/access_log,收集所需时间段内的数据并发出单个批处理请求(和/或在单个流程中进行多个单独的请求) )访问Google Analytics(分析),并提供最近5分钟内有关每个访问者的必要信息。您可以将其作为守护进程运行,也可以作为cron作业中的脚本运行,请参见crontab(5)crontab(1)

  • 或者,如果您仍希望对Google Analytics(分析)进行实时处理(我不建议这样做,因为大多数这些服务本身都是在最终一致性的基础上实现的,也就是说, GA本身并不一定要保证最近XX秒/分钟/小时/等的实时准确统计信息,那么您可能想要实现某种形式的守护程序来实时处理统计信息:

    • 我的建议仍然是在这样的守护进程中使用access_log,例如,通过您喜欢的编程语言中的tail -f /var/www/logs/access_log等价物,您将在其中打开{{1} }文件作为流,并在数据到达时和何时到达时对其进行处理。

    • 或者,您可以实现此守护程序以使其本身具有HTTP请求接口,并将每个传入请求复制到您的实际后端以及此额外的服务器。 您可以在非默认的auth_requestadd_after_body的帮助下,通过nginx对其进行多路复用,以对每个请求进行“免费”子请求。该子请求将转到您的服务器,例如,以Go编写。服务器将至少具有两个 goroutines :一个将进入的请求处理到队列中(通过缓冲的字符串通道实现),立即向客户端发出回复,以确保不延迟nginx上游;另一个人将通过第一个access_log接收来自第一个的请求,对其进行处理,然后向Google Analytics(分析)发送适当的请求。

最终,无论您采用哪种方式,您都可能仍想实施某种级别的批处理和/或限制,因为我想在某个时候,如果您继续发送Google Analytics(分析)本身,可能会受到限制来自同一个IP地址的请求过多,没有任何批处理实现。根据{{​​3}}和What is the rate limit for direct use of the Google Analytics Measurement Protocol API?来看,大多数图书馆似乎对每秒要发送给Google的请求数量实施内部限制。

答案 2 :(得分:2)

如果您需要将命中提交给Google Analytics(分析),那么可以轻松完成:Nginx可以即时修改页面HTML,在结束</body>标记之前嵌入GA代码:

sub_filter_once on;

sub_filter '</body>' "<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXXX-X', 'auto');
ga('send', 'pageview');
</script></body>";

location / {
}

此Nginx模块称为sub

答案 3 :(得分:1)

这是我最终的做法-基于https://github.com/vorodevops/nginx-analytics-measurement-protocol/tree/master/lua的proxy_pass而不是curl。该代码假定openresty或只是lua安装。不确定注释格式是否兼容(未经测试),因此最好在使用前将其删除。

# pick your location 

location /example {

    # invite lua to the party

    access_by_lua_block  {

        # set request parameters

        local request = {
            v = 1,
            t = "pageview",

            # don' forget to put your own property here

            tid = "UA-XXXXXXX-Y",

            # this is a "unique" user id based on a hash of ip and user agent, not too reliable but possibly best that one can reasonably do without cookies

            cid = ngx.md5(ngx.var.remote_addr .. ngx.var.http_user_agent),
            uip = ngx.var.remote_addr,
            dp = ngx.var.request_uri,
            dr = ngx.var.http_referer,
            ua = ngx.var.http_user_agent,

            # here you truncate the language string to make it compatible with the javascript format - you'll want either the first two characters like here (e.g. en) or the first five (e.g en_US) with ...1, 5

            ul = string.sub(ngx.var.http_accept_language, 1, 2)
            }

        # use the location.capture thingy to send everything to a proxy

        local res = ngx.location.capture(  "/gamp",  {
        method = ngx.HTTP_POST,
        body = ngx.encode_args(request)
        })
    }
}


# make a separate location block to proxy the request away

location = /gamp {
    internal;
    expires epoch;
    access_log off;
    proxy_pass_request_headers off;
    proxy_pass_request_body on;
    proxy_pass https://google-analytics.com/collect;
}