V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
ZE3kr
V2EX  ›  NGINX

Nginx 做代理,如何实现先立即返回空内容并结束请求,然后后台再发请求到后端服务器?

  •  
  •   ZE3kr ·
    ZE3kr · 2016-05-22 09:12:24 +08:00 · 7025 次点击
    这是一个创建于 2889 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个在自己服务器上的 Piwik 网页统计工具,服务器在纽约。日本已经有一个代理服务器,用作缓存。

    统计原理就是发一个 GET 请求给 /piwik.php ,我想是当一个请求发送到 /piwik.php 的日本的代理服务器上时, nginx 立即响应这个请求,返回 204 空内容,然后再把这个请求发送给纽约,这个可以实现吗?

    18 条回复    2016-05-23 06:56:08 +08:00
    pathletboy
        1
    pathletboy  
       2016-05-22 09:13:51 +08:00
    当然可以,用 nginx_lua
    gamexg
        2
    gamexg  
       2016-05-22 09:14:00 +08:00 via Android
    用 php 可以实现。
    nginx 不清楚
    ZE3kr
        3
    ZE3kr  
    OP
       2016-05-22 09:21:15 +08:00
    @pathletboy 请问是直接在 lua 里做请求吗? lua 如何实现先结束浏览器发出的请求然后再发请求?
    littlepanzh
        4
    littlepanzh  
       2016-05-22 10:51:47 +08:00
    可以问问 @qgy18
    他的博客统计就是服务端异步发的
    https://imququ.com/post/summary-of-my-blog-optimization.html
    canglaoshi
        5
    canglaoshi  
       2016-05-22 11:11:39 +08:00
    @littlepanzh 你的博客为毛那么快
    buliugu
        6
    buliugu  
       2016-05-22 11:16:45 +08:00
    @canglaoshi 进去第一篇就说明了啊。。。大量优化
    qgy18
        7
    qgy18  
       2016-05-22 11:21:04 +08:00
    @littlepanzh
    其实只要让你的程序在 HTTP 响应结束之后还能运行就可以了。对于 Node.js 来说,天然就是这样的。例如这是我的服务端统计代码:

    import { post } from 'request';

    let ua = this.header('user-agent');

    let data = {
    v : '1',
    t : 'pageview',
    cid : u,
    uip : ip
    };

    'dl,dt,dr,dp,ul,sd,sr,tid'
    .split(',')
    .forEach(name => data[name] = this.get(name));

    let options = {
    url : beaconURL,
    form : data,
    headers : {
    'User-Agent' : ua
    }
    };

    post(options); //这里是异步的

    this.header('Cache-Control', 'no-cache');
    this.status(204);
    this.end();
    littlepanzh
        8
    littlepanzh  
       2016-05-22 11:26:34 +08:00
    @qgy18 啊原来统计的请求是 nodejs 里面做的,那异步自然不是问题。我一直以为是 nginx 发的,所以感觉你用了什么其它黑科技~
    qgy18
        9
    qgy18  
       2016-05-22 11:29:13 +08:00
    @littlepanzh
    Nginx 中 proxy_pass 给统计收集地址也可以吧,实际上就是用反向代理加速。
    littlepanzh
        10
    littlepanzh  
       2016-05-22 11:31:52 +08:00
    @qgy18
    对,但是 proxy_pass 应该是同步的吧,没办法实现 lz 的要求了
    qgy18
        11
    qgy18  
       2016-05-22 11:35:26 +08:00
    @littlepanzh
    用 lua 在 Nginx 的 NGX_HTTP_LOG_PHASE 阶段异步发请求应该可以,不过我没试过。

    还有一个办法:在 WEB 应用里生产日志,另外写一个后台程序去消费日志(发给第三方统计服务)。
    littlepanzh
        12
    littlepanzh  
       2016-05-22 11:43:20 +08:00
    @qgy18
    lua 楼上有人提到了~
    读日志是个不错的主意
    点赞~
    Daniel65536
        13
    Daniel65536  
       2016-05-22 15:27:44 +08:00 via iPhone   ❤️ 2
    nginx 自带的功能就可以实现,具体是用 post_action 这个没有被非公开的功能。在 nginx 早期版本因为缺少线程池功能,用这个会堵塞 worker ,所以 nginx 的文档里都没有提到这个东西, 1.9.x 之后有了线程池,就可以比较安全地使用了。
    https://darknode.in/network/nginx-google-analytics/ 介绍了在用户访问了页面之后让 nginx 向 ga 发送一个请求的方法,你这个需求参考下改改就好。
    ZE3kr
        14
    ZE3kr  
    OP
       2016-05-22 16:58:01 +08:00
    @Daniel65536 竟然还有这个功能,现在非常好!

    ```
    location @tracker {
    internal;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_method GET;
    proxy_pass http://backend;
    proxy_set_header User-Agent $http_user_agent;
    }

    location /piwik.php {
    post_action @tracker;
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
    return 204;
    }

    location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_hide_header Vary;
    proxy_pass http://backend;
    proxy_cache webserver;
    }
    ```
    soulteary
        15
    soulteary  
       2016-05-22 17:43:03 +08:00   ❤️ 1
    粗浅的做过公司统计服务的飘过。

    方案一:直接使用 Nginx 之类的 proxy_pass 是最省事方案,就像你 #14L 做的那样。

    ---

    方案二:使用脚本做接口代理,诸如 @qgy18 屈屈给的方案。这个方案适合直接使用三方服务的场景,后端分析代码可以定制程度有限,接触不到数据库,或者定制比较麻烦。

    ---

    方案三:分析日志并导入统计应用数据库。适合不能保障网站和统计服务器连通性的情况,或者网站峰值访问略大,统计服务器有鸭梨,以及需要对统计数据做处理(清洗等)的场景。

    ---


    如果喜欢折腾,可以使用方案二或者三,如果自己能操作统计应用 /数据库,完全可以使用定期同步和分析 log 并导入统计服务的方案。
    xiaotianhu
        16
    xiaotianhu  
       2016-05-22 19:04:57 +08:00
    php+ng 用 fastcgi_finish_request 在 index 里立马返回就可以了

    http://rainyluo.net/post/php_echo_speedup
    rrfeng
        17
    rrfeng  
       2016-05-22 19:08:57 +08:00
    其实 openresty 里有大量的这种写法……

    楼上有人说 post_action ,学习了!
    klausgao
        18
    klausgao  
       2016-05-23 06:56:08 +08:00 via iPhone
    呃我感觉楼主和楼上的都想复杂了。
    前端页面统计不过就是一个 post 的问题,页面访问的时候,前端直接 post 数据到统计服务器就 OK 了,干嘛要绕到后端来处理?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1026 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 19:13 · PVG 03:13 · LAX 12:13 · JFK 15:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.