利用 nginx-upload-module 扩展直接上传至 nginx


本文档介绍了 jQuery FileUpload 插件如何使用 vkholodkov 的 nginx-upload-module 扩展进行配置(https://github.com/vkholodkov/nginx-upload-module)。其实有很多配置示例已经能覆盖绝大多数的配置需求,不过如果你使用了本套配置,你能得到以下几点好处:

  • 整个上传过程将不再存在“中间商”。你可以不用在后端运行一个 PHP 或 Node 程序来接收文件,nginx 将接手这项工作。这也就意味着你可以将上传工作分摊到其他服务器上,而不用将文件上传和你的 Web 应用捆绑起来,从而一定程度上降低你 Web 服务器的负载。
  • 支持 CORS 下的断点续传和分块上传配置。
  • 你可以在任何平台上使用本套配置,无论是 PHP、Ruby、Java 还是其他任何平台。因为你所有需要的仅仅是结合本插件和本套上传模块的配置加载到 nginx 上。

第 1 节:配置 jQuery FileUpload 插件


下面的链接是我们自定义的一组上传界面的示例。该 demo 没有选择成熟的 UI 插件,而是简化成一个足够简洁的界面。

第 2 节:FileUpload 插件的 nginx 配置


下面的链接是一个 nginx 配置文件示例,它是一组能接收不同源端并支持分块上传的配置。该 nginx 文件假定你在同一个网络环境内运行着多个 web 应用,并且你的 web 应用已配置为在上传完成时能接收 nginx 消息(200 状态和 uploaded 信息)。

上面文件中有几项重要配置虽然已经记录在 github 文档中,但我还是想提出来强调一下。

首先,确保将 client_body_buffer_size 设置为不大于上传器的 maxChunkSize。不能超过 nginx 缓存这一点非常重要,否则你可能会出现上传意外终止的情况。下面的文本文件,记录了各种 maxChunkSize 和 client_body_buffer_size 搭配下的上传压测情况。这份数据可能不能完全适用于你的环境,所以有必要的话请根据你的实际情况进行修改吧。

其次,nginx 上传模块定义了一个 upload_add_header 函数来设置必要 header。我上面提供的示例演示了如何支持 CORS。如果仅有 nginx 的常规 header 而缺少示例中的 header,会导致你无法进行跨域上传。

最后,确保你的目录结构中已经为你想上传的位置创建好上传目录(注意设置为可写权限)。上传目录要为所有数字字母(a-zA-Z0-9)都建一个文件夹。好比如你打算让 /var/uploads 作为你的上传目录,那你要在 /var/uploads 目录下给每一个数字字母建一个文件夹。这是一个必要步骤,它与本 nginx 模块和 sessionID header 设置的内部逻辑有关。

第 3 节:整合并开始运行


假如你已经准备就绪,那你的应用架构应该是这样的:

  • 应用 A(www.somesite.com):使用 jQuery FileUpload 插件为你的用户建一个上传 UI 界面。该上传器会提交到一个其他域名(www.my-upload-endpoint.com/upload)去进行上传处理。前端应用会等待直至后端应用在上传完成后进行响应。
  • 应用 B(www.my-upload-endpoint.com/upload):运行的是 nginx 来处理文件上传,然后转发响应到应用客户端。你的应用程序可以直接返回从 nginx 拿到的信息,这样应用 A 能接收到所有上传文件的返回状态。你可能需要稍微修改下响应内容,具体取决于你所要返回的数据格式长什么样。前文示例中的脚本有说明指定的数据格式,可能可以给你提供一些参考。
注意:当进行分块上传时,每一文件块上传成功后应返回 201 Created 状态码。当最后一块完成上传后,这时才返回 200 OK。
对于不便访问 github 的用户,可以通过 http://oss.cndoc.wiki/cndoc/10/code/nginx-upload-module-v2.2.1.zip 获取源码