bianbian coding life

便便代码人生: 关注技术, 翻译文档, 偶尔动动手

[译]利用Nginx的X-Accel-Redirect头实现下载控制(附带php和rails实例)

Posted by bianbian on 2007-04-05 16:40

本文Tags: , ,

有时你可能需要实现控制下载:即将下载文件的请求转发到某脚本, 然后由这脚本决定怎么做:发送这个文件给用户,出现决绝访问页,或着其他的事。在lighttpd服务器里可以通过从脚本传回X-Sendfile头实现;而Nginx是通过使用X-Accel-Redirect头实现的。在这篇文章里我会尽量简捷地描述在php和rails里如何使用这一特性。

假设你使用Apache运行PHP或Rails产生动态内容,而用Nginx作为前台反向代理(bianbian注:反向代理又称为服务器加速(Server accelerate),原理是将用户的请求转发到目标服务器,然后将结果转发给用户。好处有很多:保护目标服务器安全、负载均衡容易实现、有点类似防火墙;坏处我认为就是要传递用户的IP的时候多了些步骤)。你就达到了两个目标:

  1. 因为Nginx服务器会改善所有对动态内容的缓慢请求,能节省服务器的资源(细节正在
    这里). (bianbian注:凭我对Nginx的理解,这个就是Nginx会缓存客户端的请求,等全部发送完毕了才一起转发给后台脚本,比如在上载文件的时候。好处是减少后台脚本等待的时间,确实对性能有一定改善;坏处就是在脚本里时时显示上载进度的功能是不可能实现了[当然,以后Nginx如果自己开放这个进度API也是可能的,不过也不是脚本级的,好在显示进度的功能不常用])
  2. 你能对静态文件的下载做出控制.(bianbian注:后面的一大段都是说这个啦!)

在这里,假设网站位于 /var/www 目录,而一些静态文件(类似电影、歌曲、或其他)位于 /var/www/files 目录。Apache监听8080端口。

首先,让我们看一看nginx配置:

  1. http {
  2.     ....
  3.     server {
  4.         listen       80;
  5.         server_name  your-domain.com;
  6.  
  7.         location / {
  8.             rewrite ^/download/(.*) /down.php?path=$1 last;
  9.  
  10.             proxy_pass         http://127.0.0.1:8080/;
  11.             proxy_redirect     off;
  12.  
  13.             proxy_set_header   Host             $host;
  14.             proxy_set_header   X-Real-IP        $remote_addr;
  15.             proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
  16.  
  17.             client_max_body_size       10m;
  18.             client_body_buffer_size    128k;
  19.  
  20.             proxy_connect_timeout      90;
  21.             proxy_send_timeout         90;
  22.             proxy_read_timeout         90;
  23.  
  24.             proxy_buffer_size          4k;
  25.             proxy_buffers              4 32k;
  26.             proxy_busy_buffers_size    64k;
  27.             proxy_temp_file_write_size 64k;
  28.  
  29.         }
  30.  
  31.         location /files {
  32.             root /var/www;
  33.             internal;
  34.         }
  35.     }
  36. }

关键字“internal”指明了哪些目录需要通过X-Accel-Redirect头与后台脚本进行内部转向。我们的脚本只需要完成下载控制的部分,至于分段下载等其他特性跟一般的静态文件一样,都由Nginx服务器实现。
这里是 down.php 的内容:

  1. <?php
  2. // 得到要下载的文件名
  3. $path = $_GET["path"];
  4.  
  5. //...
  6. // 这里完成权限校验、下载统计等等
  7. //...
  8.  
  9. // 重定向完成下载
  10. header("X-Accel-Redirect: /files/" . $path);
  11. ?>

在 Rails 里可以在控制(controller)里写如下代码(bianbian注:Rails是约定好的MVC架构):

  1. # 得到要下载的文件名
  2. path = @params["path"]
  3.  
  4. # ...
  5. # 这里完成权限校验、下载统计等等
  6. # ...
  7.  
  8. # 重定向完成下载
  9. @response.headers['X-Accel-Redirect'] = "/files/" + path

这样就完成了!用上述方法我们就能创建非常灵活又极度高效的文件分发系统。

原文链接:Using X-Accel-Redirect Header With Nginx to Implement Controlled Downloads (with rails and php examples)

标签: , ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

4 Responses to “[译]利用Nginx的X-Accel-Redirect头实现下载控制(附带php和rails实例)”

  1. bianbian Says:

    使用注意,有时候需要加上:
    proxy_hide_header Content-Type;

  2. bianbian Says:

    测试成功!!!请大家注意:
    internal 关键字必须要有!internal指明了必须通过内部才能下载(避免直接输链接)。
    如果忘记了internal,即使后台fastcgi输出X-Accel-Redirect也没有用!
    那么,如果有些文件又允许直接下载,又允许fastcgi来转向下载怎么办呢?
    还好linux有link文件,用“ln -s”建立一个软指向目录就可以了!
    两个小时的血泪经验阿,晕倒~

  3. 王猛 Says:

    谢谢,我一直找X-SENDFILE做什么用的,在这里终于找到了答案。
    虽然这里说的是Nginx的X-Accel-Redirect但是Apache的X-SENDFILE同样可以支持!
    方法也是类似的!

    http://celebnamer.celebworld.ws/stuff/mod_xsendfile/

  4. Anonymous Says:

    files目录下还有分类目类,每个分类目录存放不同类型的文件,这时候返回的是404,要怎样解决?

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

(required)