基于这种情况,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.test.com;
}
这样,用户访问如http://www.test.com/mp3/1.mp3这样的地址时,将不能下载文件,nginx会把请求交给后端服务器。
2、在后端服务器配置一个rewrite
rewrite "^/mp3/(.*)\.mp3$" /read_file.do?id=$1 last;
这个rewrite的目的是把请求http://www. test.com/mp3/1.mp3指向到一个php程序语言上,由程序语言处理。
3、写一个java程序判断权限
httpResponse.setHeader("Content-Disposition", "attachment; filename=\""+filename+"\"");
httpResponse.setHeader("Content-Type","application/octet-stream");
httpResponse.setHeader("X-Accel-Redirect","/mp3/"+resource.get("res_url"));
//给nginx返回实际文件存在的地址
这样,配置就完成了。