Resumable 文件分块上传

Resumable.js

提供多个同时上传,稳定的可以撤销的文件上传(使用HTML的文件API)

It’s a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API.

使用HTTP协议上传大文件:通过把一个文件分割成晓得chunks,如果上传一个chunk失败后,上传还会继续直到上传过程结束(传统过程中如果上传出现问题,服务器可能卡住)。当网络中途断开后(不管是本地还是服务器断开),这个库允许继续自动上传。除此之外,可以允许用户在上传过程中暂停或者继续上传任务。

The library is designed to introduce fault-tolerance into the upload of large files through HTTP. This is done by splitting each files into small chunks; whenever the upload of a chunk fails, uploading is retried until the procedure completes. This allows uploads to automatically resume uploading after a network connection is lost either locally or to the server. Additionally, it allows for users to pause, resume and even recover uploads without losing state.

这个库不依赖其他的库(只利用原生的File API)。这个依赖于一个文件可以分成很多小块。兼容性:支持FF 4 和 chrome 11以后的版本。

Resumable.js does not have any external dependencies other the HTML5 File API. This is relied on for the ability to chunk files into smaller pieces. Currently, this means that support is limited to Firefox 4+ and Chrome 11+.

下面是后端基于 python Flask 框架的源码

from flask import Flask, render_template, request, abort, jsonify
import os
app = Flask(__name__)
app.debug = True

temp_base = os.path.expanduser("~/tmp/flask_uploads/")

# landing page
@app.route("/resumable")
def resumable_example():
    return render_template("resumable_upload.html")

# resumable.js uses a GET request to check if it uploaded the file already.
# NOTE: your validation here needs to match whatever you do in the POST (otherwise it will NEVER find the files)
@app.route("/resumable_upload", methods=['GET'])
def resumable():
    resumableIdentfier = request.args.get('resumableIdentifier', type=str)
    resumableFilename = request.args.get('resumableFilename', type=str)
    resumableChunkNumber = request.args.get('resumableChunkNumber', type=int)

    if not resumableIdentfier or not resumableFilename or not resumableChunkNumber:
        # Parameters are missing or invalid
        abort(500, 'Parameter error')

    # chunk folder path based on the parameters
    temp_dir = os.path.join(temp_base, resumableIdentfier)

    # chunk path based on the parameters
    chunk_file = os.path.join(temp_dir, get_chunk_name(resumableFilename, resumableChunkNumber))
    app.logger.debug('Getting chunk: %s', chunk_file)

    if os.path.isfile(chunk_file):
        # Let resumable.js know this chunk already exists
        return 'OK'
    else:
        # Let resumable.js know this chunk does not exists and needs to be uploaded
        abort(404, 'Not found')


# if it didn't already upload, resumable.js sends the file here
@app.route("/resumable_upload", methods=['POST'])
def resumable_post():
    resumableTotalChunks = request.form.get('resumableTotalChunks', type=int)
    resumableChunkNumber = request.form.get('resumableChunkNumber', default=1, type=int)
    resumableFilename = request.form.get('resumableFilename', default='error', type=str)
    resumableIdentfier = request.form.get('resumableIdentifier', default='error', type=str)

    # get the chunk data
    chunk_data = request.files['file']

    # make our temp directory
    temp_dir = os.path.join(temp_base, resumableIdentfier)
    if not os.path.isdir(temp_dir):
        os.makedirs(temp_dir, 0777)

    # save the chunk data
    chunk_name = get_chunk_name(resumableFilename, resumableChunkNumber)
    chunk_file = os.path.join(temp_dir, chunk_name)
    chunk_data.save(chunk_file)
    app.logger.debug('Saved chunk: %s', chunk_file)

    # check if the upload is complete
    chunk_paths = [os.path.join(temp_dir, get_chunk_name(resumableFilename, x)) for x in range(1, resumableTotalChunks+1)]
    upload_complete = all([os.path.exists(p) for p in chunk_paths])

    # combine all the chunks to create the final file
    if upload_complete:
        target_file_name = os.path.join(temp_base, resumableFilename)
        with open(target_file_name, "ab") as target_file:
            for p in chunk_paths:
                stored_chunk_file_name = p
                stored_chunk_file = open(stored_chunk_file_name, 'rb')
                target_file.write(stored_chunk_file.read())
                stored_chunk_file.close()
                os.unlink(stored_chunk_file_name)
        target_file.close()
        os.rmdir(temp_dir)
        app.logger.debug('File saved to: %s', target_file_name)

    return 'OK'


def get_chunk_name(uploaded_filename, chunk_number):
    return uploaded_filename + "_part_%03d" % chunk_number

下面是前端基于 jquery 的代码

<div class="resumable-drop">
  Drop video files here to upload or <a class="resumable-browse"><u>select from your computer</u></a>
</div>

<div class="progress" style="display:none;">
  <table>
    <tr>
      <td width="100%"><div class="progress-container"><div class="progress-bar"></div></div></td>
      <td class="progress-text" nowrap="nowrap"></td>
      <td class="progress-pause" nowrap="nowrap">
        <a href="#" onclick="uploader.resumable.upload(); return(false);" class="progress-resume-link"><img src="/resources/um/graphics/uploader/resume.png" title="Resume upload" /></a>
        <a href="#" onclick="uploader.resumable.pause(); return(false);" class="progress-pause-link"><img src="/resources/um/graphics/uploader/pause.png" title="Pause upload" /></a>
      </td>
    </tr>
  </table>
</div>

<div class="uploader-list" style="display:none;">
  <div class="uploader-item">
    ... (generated thumbnails for each file)
  </div>
</div>

<div class="file-edit-container" style="display:none;">
  ... (elements for the edit UI)
</div>

<script src="/resources/um/script/resumable.js"></script>
<script src="/resources/um/script/resumable-uploader.js"></script>
<script>
  uploader = (function($){
      var upload_token = '<api upload token>';
      var meta = {};
      return (new ResumableUploader(upload_token, meta, $('.resumable-browse'), $('.resumable-drop'), $('.progress'), $('.uploader-list'), $('.file-edit-container')));
    })(jQuery);
</script>

How can I use it?

A new Resumable object is created with information of what and where to post:

首先,创建一个 Resumable 的实例(包括请求的内容和请求的地址)

var r = new Resumable({
  target:'/api/photo/redeem-upload-token', 
  query:{upload_token:'my_token'}
});
// Resumable.js isn't supported, fall back on a different method
if(!r.support) location.href = '/some-old-crappy-uploader';

To allow files to be either selected and drag-dropped, you’ll assign drop target and a DOM item to be clicked for browsing:

r.assignBrowse(document.getElementById('browseButton'));
r.assignDrop(document.getElementById('dropTarget'));

After this, interaction with Resumable.js is done by listening to events:

r.on('fileAdded', function(file){
    ...
  });
r.on('fileSuccess', function(file,message){
    ...
  });
r.on('fileError', function(file, message){
    ...
  });

How do I set it up with my server?

这里是服务器端配置(处理HTTP请求)

Most of the magic for Resumable.js happens in the user’s browser, but files still need to be reassembled from chunks on the server side. This should be a fairly simple task and can be achieved in any web framework or language, which is able to receive file uploads.

To handle the state of upload chunks, a number of extra parameters are sent along with all requests:

  • resumableChunkNumber: The index of the chunk in the current upload. First chunk is 1 (no base–0 counting here).
  • resumableChunkSize: The general chunk size. Using this value and resumableTotalSize you can calculate the total number of chunks. Please note that the size of the data received in the HTTP might be lower than resumableChunkSize of this for the last chunk for a file.
  • resumableTotalSize: The total file size.
  • resumableIdentifier: A unique identifier for the file contained in the request.
  • resumableFilename: The original file name (since a bug in Firefox results in the file name not being transmitted in chunk multipart posts).
  • resumableRelativePath: The file’s relative path when selecting a directory (defaults to file name in all browsers except Chrome).

You should allow for the same chunk to be uploaded more than once; this isn’t standard behaviour, but on an unstable network environment it could happen, and this case is exactly what Resumable.js is designed for.

For every request, you can confirm reception in HTTP status codes:

  • 200: The chunk was accepted and correct. No need to re-upload.
  • 415. 500, 501: The file for which the chunk was uploaded is not supported, cancel the entire upload (in fact, any >=400 HTTP status code will trigger this result, see details.
  • Anything else: Something went wrong, but try reuploading the file.

Handling GET (or test() requests)

This will allow uploads to be resumed after browser restarts and even across browsers (in theory you could even run the same file upload across multiple tabs or different browsers). The POST data requests listed are required to use Resumable.js to receive data, but you can extend support by implementing a corresponding GET request with the same parameters:

  • If this request returns a 200 HTTP code, the chunks is assumed to have been completed.
  • If the request returns anything else, the chunk will be uploaded in the standard fashion.

Full documentation

Resumable

Configuration

The object is loaded with a configuation hash:

var r = new Resumable({opt1:'val', ...});

Available configuration options are:

  • target The target URL for the multipart POST request (Default: /)
  • chunkSize The size in bytes of each uploaded chunk of data (Default: 1*1024*1024)
  • simultaneousUploads Number of simultaneous uploads (Default: 3)
  • fileParameterName The name of the multipart POST parameter to use for the file chunk (Default: file)
  • query Extra parameters to include in the multipart POST with data. This can be an object or a function. If a function, it will be passed a ResumableFile object (Default: {})
  • headers Extra headers to include in the multipart POST with data (Default: {})
  • prioritizeFirstAndLastChunk Prioritize first and last chunks of all files. This can be handy if you can determine if a file is valid for your service from only the first or last chunk. For example, photo or video meta data is usually located in the first part of a file, making it easy to test support from only the first chunk. (Default: false)
  • testChunks Make a GET request to the server for each chunks to see if it already exists. If implemented on the server-side, this will allow for upload resumes even after a browser crash or even a computer restart. (Default: true)
  • generateUniqueIdentifier Override the function that generates unique identifiers for each file. (Default: null)
  • maxFiles Indicates how many files can be uploaded in a single session. Valid values are any positive integer and undefined for no limit. (Default: undefined)
  • maxFilesErrorCallback A function which displays the please upload n file(s) at a time message. (Default: displays an alert box with the message Please n one file(s) at a time.)
Properties
  • .support A boolean value indicator whether or not Resumable.js is supported by the current browser.
  • .opts A hash object of the configuration of the Resumable.js instance.
  • .files An array of ResumableFile file objects added by the user (see full docs for this object type below).
Methods
  • .assignBrowse(domNodes, isDirectory) Assign a browse action to one or more DOM nodes. Pass in true to allow directories to be selected (Chrome only).
  • .assignDrop(domNodes) Assign one or more DOM nodes as a drop target.
  • .on(event, callback) Listen for event from Resumable.js (see below)
  • .upload() Start or resume uploading.
  • .pause() Pause uploading.
  • .cancel() Cancel upload of all ResumableFile objects and remove them from the list.
  • .progress() Returns a float between 0 and 1 indicating the current upload progress of all files.
  • .isUploading() Returns a boolean indicating whether or not the instance is currently uploading anything.
  • .removeFile(file) Cancel upload of a specific ResumableFile object on the list from the list.
  • .getFromUniqueIdentifier(uniqueIdentifier) Look up a ResumableFile object by its unique identifier.
  • .getSize() Returns the total size of the upload in bytes.
Events
  • .fileSuccess(file) A specific file was completed.
  • .fileProgress(file) Uploading progressed for a specific file.
  • .fileAdded(file) A new file was added.
  • .fileRetry(file) Something went wrong during upload of a specific file, uploading is being retried.
  • .fileError(file, message) An error occured during upload of a specific file.
  • .complete() Uploading completed.
  • .progress() Uploading progress.
  • .error(message, file) An error, including fileError, occured.
  • .pause() Uploading was paused.
  • .cancel() Uploading was canceled.
  • .catchAll(event, ...) Listen to all the events listed above with the same callback function.

ResumableFile

Properties
  • .resumableObj A back-reference to the parent Resumable object.
  • .file The correlating HTML5 File object.
  • .fileName The name of the file.
  • .relativePath The relative path to the file (defaults to file name if relative path doesn’t exist)
  • .size Size in bytes of the file.
  • .uniqueIdentifier A unique identifier assigned to this file object. This value is included in uploads to the server for reference, but can also be used in CSS classes etc when building your upload UI.
  • .chunks An array of ResumableChunk items. You shouldn’t need to dig into these.
Methods
  • .progress(relative) Returns a float between 0 and 1 indicating the current upload progress of the file. If relative is true, the value is returned relative to all files in the Resumable.js instance.
  • .abort() Abort uploading the file.
  • .cancel() Abort uploading the file and delete it from the list of files to upload.
  • .retry() Retry uploading the file.
  • .bootstrap() Rebuild the state of a ResumableFile object, including reassigning chunks and XMLHttpRequest instances.

Alternatives

This library is explicitly designed for modern browsers supporting advanced HTML5 file features, and the motivation has been to provide stable and resumable support for large files (allowing uploads of several GB files through HTTP in a predictable fashion).

If your aim is just to support progress indications during upload/uploading multiple files at once, Resumable.js isn’t for you. In those cases, SWFUpload and Pluploadprovides the same features with wider browser support.

现在先了解基本原理,后续会继续学习。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 前端可以通过以下几种方法来解决上传文件太大的问题: 1. 限制文件大小:在前端代码中限制上传文件的大小,如果文件太大,就提示用户选择一个较小的文件。 2. 分块上传:将文件分成多个小块,分别上传,这样即使文件很大,也不会占用太多的内存。 3. 压缩文件:在前端压缩文件,使得文件体积变小,再上传。 4. 后端处理:如果前端无法处理,也可以在后端进行处理,例如将大文件分块存储。 选择具体的解决方案取决于具体的需求和约束条件。 ### 回答2: 前端可以通过以下几种方式解决上传文件太大的问题。 1. 文件大小限制:前端可以通过在文件上传控件中设置文件大小限制,限制用户上传文件最大大小。可以使用HTML5的File API来检查文件的大小,在选择文件之前进行检查并给予用户相应的提示。 2. 断点续传:前端可以使用断点续传技术,将大文件分成多个小文件进行上传。当上传中断时,用户重新上传时只需要上传断点之后的文件部分,避免重复上传整个大文件。可以使用HTML5的File API对文件进行切割,或者使用第三方库进行切割和上传。 3. 压缩文件:前端可以在上传之前对大文件进行压缩,减小文件的大小。可以使用第三方的文件压缩库进行文件压缩,然后再进行上传。 4. 服务器分片上传:将大文件分成多个小分片,分别上传到服务器。前端可以使用HTML5的File API对文件进行切割,将切割后的小分片并发地上传到服务器。服务器端接收到多个小分片后再进行合并。 5. 服务器端限制:前端可以向服务器发送文件大小等信息,并在服务器端进行判断和限制。服务器端可以设置接收文件的最大大小,当前端上传文件超过服务器的限制时,服务器拒绝接收并返回相应提示给前端。 总而言之,前端可以通过文件大小限制、断点续传、文件压缩、服务器分片上传和服务器端限制等方式来解决上传文件太大的问题。不同的解决方案可以根据实际情况进行选择和组合使用。 ### 回答3: 当遇到上传文件太大的问题,前端可以采取以下方法来解决: 1. 设置前端限制:可以在前端进行文件大小的限制。通过在文件上传的表单元素中添加"accept"属性,并指定文件类型,例如"accept=".png,.jpg",可以限制只接受指定类型的文件。另外,在表单元素中添加"maxlength"属性,可以限制上传文件大小,避免上传过大文件。 2. 对文件进行压缩:前端可以使用压缩算法,将文件进行压缩再上传。通过压缩文件,可以减小文件大小,提高上传速度。可以使用一些前端框架或者第三方库,如JSZip、image-compressor等来实现文件压缩功能。 3. 分片上传:将大文件分成小块进行上传。前端可以使用分片上传的方式,将文件分成多个小块,逐个进行上传。这样可以避免一次性上传文件,减轻服务器负担,提高上传速度。一些前端框架或者第三方库,如Resumable.js、plupload等可以辅助实现分片上传功能。 4. 服务端限制:与前端限制结合使用,后端也可以对上传文件大小进行限制。在服务器端设置上传文件的大小限制,当文件超过限制大小时,可以返回错误信息,提醒用户重新选择文件或者压缩文件后再上传。 综上所述,前端可以通过设置前端限制、对文件进行压缩、分片上传以及结合后端限制来解决上传文件太大的问题。通过这些方法,可以有效地减小上传文件的大小,提高文件上传的效率和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值