最近做的项目有个工具库模块,需要实现工具的上传与下载。上传与下载都使用的是Laravel内置的方法,本来都没什么问题,今天无意上传了一个两百多M的文件,上传很顺利,但当点击下载时,发现会出现下载回来的数据不全的情况。暂时没找到是什么原因,估计是内存方面的问题。
修改了几次代码后都无法解决,那就只能换一种方式了。多次搜索后,发现了一种直接返回 x-sendfile 头实现文件下载方式,完美的解决了我的问题。
Nginx
Nginx默认支持x-sendfile模式,所以使用起来十分方便。
配置虚拟域名的配置文件,添加如下内容
1 2 3 4 5
| #伪造下载路径 location /down/{ internal; #只允许内部访问,防止盗链 alias /home/www/myweb/public/uploads/utool/; }
|
1 2 3 4 5
| $filename = 'test.zip'; $file_path = '/down/test.zip'; header('Content-type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.$filename.'"'); header('X-Accel-Redirect:'.$file_path);
|
就这么轻松的两步就实现了大文件的下载,是不是很简单。
Apache
Apache需要加载 module mod_xsendfile 模块来实现相对应的功能,所以稍微复杂一点
加载 module mod_xsendfile
从项目地址上下载对应的 mod_xsendfile.so,放到apache的modules目录下.然后修改 http.conf ,添加如下内容
1
| LoadModule xsendfile_module modules/mod_xsendfile.so
|
开启 xsendfile
修改虚拟域名的配置文件,添加如下内容
1 2 3 4 5 6 7 8
| XSendFile On <Directory "D:/wamp/www/myweb/public/uploads/utool/"> <IfDefine APACHE24> Require local </IfDefine> </Directory>
|
1 2 3 4 5
| $filename = 'test.zip'; $file_path = 'D:/wamp/www/myweb/public/uploads/utool/test.zip'; header('Content-type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.$filename.'"'); header('X-Sendfile:'.$file_path);
|
使用 x-sendfile 模式后,PHP只需返回header头,后续就不需要处理,所以效率有了明显提升。
如果在下载过程中,出现中文文件名乱码的情况,可以使用函数 rawurlencode 对文件名做转码,这样就能解决乱码问题。