前一篇文章介绍了一下nginx的断点上传模块:

这个模块支持断点上传,但是需要客户端预先对文件分段,然后挨个上传分段。如果某个分段上传一半中断了,那么必须重新上传整个分段。所以就带来两个问题:

  1. 分段重传,做了一部分无用功。
  2. 每上传一个分段,重新建立tcp连接的开销。

于是对这个模块做了一些改动,在分段上传发生异常中断时,将已经写入磁盘的部分记录到state文件中。这样只要客户端发起一次少量的数据上传,就能查询到当前文件已经上传了那些分段,然后可以从中断的地方继续上传。这样一次POST可以上传尽可能多的数据。 当然,如果使用多线程上传,那还是需要预先分段。

代码地址:https://github.com/bigplum/nginx-upload-module/tree/2.2

主要增加了一个cleanup函数,判断如果文件的offset不等于content range end,那么就做一次merge range操作。

static void
ngx_http_upload_cleanup_part(void *data)
{
    ngx_http_request_t *r = data;
    ngx_http_upload_ctx_t     *u;
    ngx_int_t                 rc;
    ngx_http_upload_range_t     content_range_n;

    u = ngx_http_get_module_ctx(r, ngx_http_upload_module);
    if(!u){
        return;
    }
    
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "cleanup http upload request, out offset: %d", u->output_file.offset);
    
    if(!u->raw_input || !u->output_file.offset || 
        u->output_file.offset == u->content_range_n.end + 1)
    {
        return;
    }

    content_range_n.start = u->content_range_n.start;
    content_range_n.end = u->output_file.offset - 1;
    content_range_n.total = u->content_range_n.total;

    rc = ngx_http_upload_merge_ranges(u, &content_range_n);

    if(rc == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0
            , "upload cleanup: error merging ranges"
            );

        return;
    }
}

Simon Lee

My blog