使用nginx的X-Accel-Redirect头实现下载控制

发布时间:2020-09-19编辑:脚本学堂
本文介绍下,借助nginx的X-Accel-Redirect头实现下载控制的方法,并附有php与rails的例子,有需要的朋友参考下。

所谓控制下载:即将下载文件的请求转发到某脚本, 然后由这脚本决定怎么做:
发送这个文件给用户,出现决绝访问页,或其它操作。

在lighttpd服务器里可以通过从脚本传回X-Sendfile头实现;
nginx是通过使用X-Accel-Redirect头实现的。

假设使用apache运行PHP或Rails产生动态内容,而用Nginx作为前台反向代理(bianbian注:

反向代理又称为服务器加速(Server accelerate),原理是将用户的请求转发到目标服务器,然后将结果转发给用户。好处有很多:保护目标服务器安全、负载均衡容易实现、有点类似防火墙;坏处就是要传递用户的IP时多了些步骤)。

1. 因为Nginx服务器会改善所有对动态内容的缓慢请求,能节省服务器的资源(细节正在这里)。
Nginx会缓存客户端的请求,等全部发送完毕了才一起转发给后台脚本,比如在上载文件时。

好处是减少后台脚本等待的时间,确实对性能有一定改善;
坏处就是在脚本里时时显示上载进度的功能是不可能实现了。

2. 能对静态文件的下载做出控制。

以下的内容,假设网站位于 /var/www 目录,而静态文件位于 /var/www/files 目录。
Apache监听在8080端口上。

nginx配置:
 

复制代码 代码示例:
http {
....
server {
listen   80;
server_name  www.jb200.com;
 
location / {
rewrite ^/download/(.*) /down.php?path=$1 last;
 
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
 
proxy_set_header   Host $host;
proxy_set_header   X-Real-IP$remote_addr;
proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
 
client_max_body_size   10m;
client_body_buffer_size128k;
 
proxy_connect_timeout  90;
proxy_send_timeout 90;
proxy_read_timeout 90;
 
proxy_buffer_size  4k;
proxy_buffers  4 32k;
proxy_busy_buffers_size64k;
proxy_temp_file_write_size 64k;
}
 
location /files {
root /var/www;
internal;
}
}
}
 

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

php代码内容:
 

复制代码 代码示例:
<?php
// 得到要下载的文件名
$path = $_GET["path"];
 
//...
// 此处完成权限校验、下载统计等
//...
 
// 重定向完成下载
header("X-Accel-Redirect: /files/" . $path);
?>

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

复制代码 代码示例:
# 得到要下载的文件名
path = @params["path"]
 
# ...
# 这里完成权限校验、下载统计等等
# ...
 
# 重定向完成下载
@response.headers['X-Accel-Redirect'] = "/files/" + path

用上述方法就能创建非常灵活又极度高效的文件分发系统。

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

另外,internal 关键字必须要有!internal指明了必须通过内部才能下载(避免直接输链接)。
如果忘记了internal,即使后台fastcgi输出X-Accel-Redirect也没有用。
那么,如果有些文件又允许直接下载,又允许fastcgi来转向下载,应该如何操作呢?
还好linux有link文件,用“ln -s”建立一个软指向目录就可以了。