在web应用中,常常会有文件需要下载。如果这些文件是非常私密的,直接用web服务器下载,就不能检查文件的下载权限。以往遇到这种需要权限的情况,都 是用程序语言判定权限后,使用程序语言来读取文件并输出,这样就能解决权限问题。但是使用程序语言来读取文件又带来了效率上的问题,如果文件体积比较大或 者下载并发数比较大,服务器很快就不堪重负。基于这种情况,web服务器软件提供了相应的解决办法:使用一个response header来控制下载。目前squid、apache、lighttpd、nginx等http server都有支持这种方式,但是他们的response header的名字都不一样:nginx: X-Accel-Redirect
squid: X-Accelerator-Vary
apache: X-Sendfile
lighttpd: X-Sendfile/X-LIGHTTPD-send-file用response header控制下载的原理都大同小异:当客户端发起请求下载某个文件时,因为并没有X-Accel-Redirect头,web服务器并不会立刻就把文件输出给客户端;而是将这个请求交给后端 的程序语言,程序语言验证认为该客户端可以下载这个文件,就写出相应的X-Accel-Redirect头并结束处理;X-Accel-Redirect 头返回时经过前端的web服务器,web服务器检查到这个头之后,才把文件输出到客户端。那么,如果客户端伪造一个X-Accel-Redirect头来读取呢?当然也是不能下载的,因为web服务器只认识后端发来的X-Accel-Redirect头,客户端发来的不算。于是下面就用nginx来实现上述的这个流程:1、改变目录权限,客户端发起请求时,将这个目录的请求都交给后端location /mp3/ {
alias /data/html/mp3/;
internal;
error_page 403 =200 @backend;
}location @backend {
proxy_pass http://www.sudone.com;
}这样,用户访问如http://www.sudone.com/mp3/1.mp3这样的地址时,将不能下载文件,nginx会把请求交给后端服务器。2、在后端服务器配置一个rewriterewrite "^/mp3/(.*)\.mp3$" /read_file.php?id=$1 last;这个rewrite的目的是把请求http://www.sudone.com/mp3/1.mp3指向到一个php程序语言上,由程序语言处理。3、写一个php程序判断权限如限定时间内(19点到23点)可以下载文件:
$hour=getdate()[hours];
if ($hour>=19 && $hour<=23)
{
     header("Content-Type: application/octet-stream");
     header("X-Accel-Redirect: /mp3/".$id.".mp3");
}
?>每天晚上的19点到23点访问该地址都会输出X-Accel-Redirect头,内容是文件地址。输出X-Accel-Redirect头之后,文件才能被下载,否则客户端什么都得不到。所以就实现了晚上19点到23点才能下载到文件,其他时间段就不能了。这样,配置就完成了。自己也试着配置了一把,PHP是把请求重新转发了,只是到最后一步的时候服务器总报404错误,一直找不出原因。不知道是不是跟版本有关系,自己装的nginx的version信息又被我改了所以查不到版本号。

解决方案 »

  1.   

    1楼不厚道啊,我就是看文章不明白才来这里问的,你帖的这篇文章我看过几次了,由于对apache不够熟悉没能完全看明白。
    望楼下高手解答
      

  2.   

    你有测试过吗, discuz x2支持这个功能, 改天我先测试下看看
      

  3.   


    这种情况下,你要下载的文件肯定是放在web根目录以外,也就是http直接访问是访问不了的。
    比如,http://www.123.com/ 指向目录:/home/httpd/html,下载的文件123.exe在服务器的实际路径可能就是/home/soft/123.exe,这样nginx等服务器软件可以访问,web用户却无法通过http方式来访问