利用Nginx第三方模块,实现附件打包下载

原文:利用Nginx第三方模块,实现附件打包下载php

前一阵子被一个需求困扰:附件的打包下载,须要将一批逻辑上一块儿的文件,让用户经过一个下载按钮打包下载。首先想到的方案是服务端调用什么zip之类的类库,将文件打包好后返回客户端。可是这样作有一个很明显的问题:文件不少很大的状况下,打包可能会占用大量的内存和cpu,就算在磁盘上构建临时的打包文件,也会增长服务器的磁盘IO负担,并且这些临时的文件无端占用大量的磁盘空间,删除仍是个问题。用户体验也是问题,由于必须打包完成后,才能开始返回,没法边打包边下载。原本都准备放弃了,不过发现百度网盘好像实现了这个功能,因而再次考虑如何实现。想到咱们实际上使用了Nginx做为文件服务器,会不会有第三方模块可以支持这种功能呢?寻觅以后果真有结果,就是本文要探讨的mod_ziphtml

mod_zip介绍

mod_zip可以动态的构建zip包,这种动态体如今当Nginx做为反向代理服务器的时候,该模块可以根据上游服务器返回的文件列表来打包文件。mod_zip其实是利用Nginx的subrequest功能,将zip流发送到客户端的,并且它实际上只打包不压缩,因此借助Nginx自己做为文件服务器的能力,该模块的内存占用十分少,对于上G的大文件也没有问题。zip文件自己是结构化的,能够自定义目录结构,因此对于mod_zip而言,要作的只是添加zip的头部尾部和zip内部的目录结构元数据而已,文件数据自己依靠Nginx自身的机制发送。nginx

除此以外,还有以下两点:git

  • 因为使用subrequest机制,文件甚至能够不在Nginx的服务器自己,能够是上游服务器,甚至是互联网的远程服务器上
  • 在添加crc校验后,mod_zip还可以支持HTTP的Range,支持断点续传

基本使用

安装

下载源码:github

$ git clone https://github.com/evanmiller/mod_zip.git

从新编译Nginx,不要make install:服务器

$ ./configure --add-module=/src/mod_zip
$ make

将生成的二进制文件覆盖现有的二进制文件。一般编译出来的二进制文件位于源码目录的objs/nginx。更多关于如何添加第三方模块看如何安装nginx第三方模块app

使用方法

该模块不须要在nginx.conf中配置任何东西,一切的行为取决于上游服务器的响应内容。mod_zip规定当响应头中包含X-Archive-Files的时候,将启用mod_zip的功能:dom

X-Archive-Files: zip

同时,响应的body中须要包含一个欲打包的文件的列表,如:ide

1034ab38 428    /foo.txt   My Document1.txt
83e8110b 100339 /bar.txt   My Other Document1.txt

每一行表示一个文件描述,行与行之间有一个换行符(最后也有个换行)。每行从左向右以空格分隔,依次是文件的crc-32校验,文件大小(Byte),文件的uri,文件名。其中crc-32能够忽略,并用-代替,文件名能够包含目录,会体如今最后的压缩包中的目录结构中。测试

重点是文件的uri怎么理解。这里的/foo.txt/bar.txt并不是指向文件系统的路径,而是一个子请求的地址。好比上面的/foo.txt实际上会产生一个Nginx自身的请求:http://host/foo.txt,至于这个请求获得什么又要根据nginx.conf中的配置决定了。这样的设计十分灵活,例以下面的配置:

location ~ "^/(?<srv>server[12])/(?<file>.*txt)" {
    proxy_pass http://$srv.domain.com/$file
}

因而,能够这样使用文件uri:

1034ab38 428    /server1/foo.txt   My Document1.txt
83e8110b 100339 /server2/bar.txt   My Other Document1.txt

这样两个文件分别会向远程服务器请求文件:

http://server1.domain.com/foo.txt
http://server2.domain.com/bar.txt

上游服务器能够经过在头部注入Content-Disposition来控制zip文件的输出文件名

Content-Disposition: attachment; filename=foobar.zip

上游服务器示例

下面是个测试用的上游服务器例子

<?php

    header('X-Accel-Chareset: utf-8');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=test.zip');
    header('X-Archive-Files: zip');
    $crc32 = "-";
    printf("%s %d %s %s\n", $crc32, 66382593, '/video/raw/1dc3b670-f864-4050-9772-8ccff341d091.mp4', '1.mp4');
    printf("%s %d %s %s\n", $crc32, 26160723, '/video/raw/4d6bf6ba-5b8a-49be-bede-481fe49093dc.mp4', '2.mp4');
?>
相关文章
相关标签/搜索