V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
nilai
V2EX  ›  JavaScript

javascript 上传大文件问题

  •  
  •   nilai · 2017-03-23 10:42:05 +08:00 · 3402 次点击
    这是一个创建于 2801 天前的主题,其中的信息可能已经有所发展或是发生改变。
    本地环境 chrome 53 ubuntu
    通过查询相关资料得知 chrome 对 blob 有大小限制大约在 500Mb 的样子, 由于上传过程中要对文件内容进行客户端加密(不要问为什么,就是要在客户端层面加密,跟 https 无关,也不要问这个梗为什么). 不然就直接用 webuploader 之类的了,何必自己造轮子。
    所以 上传文件就分片, 按 10MB 一个分片, 目前写的代码在传小文件,大约 300Mb 左右的时候正常,但是上传超过 1G 左右文件, 浏览器就直接报错了。

    net::ERR_FILE_NOT_FOUND

    代码很简单,根据文件大小分片,然后递归调用
    测试代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="//cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    </head>
    <body>
    <div ng-app="testapp" ng-controller="testctl">
    <input type="file" id="file">
    <input type="button" ng-click="one()" value="test_split_upload">
    </div>

    <script>

    (function () {
    'use strict';
    angular
    .module('testapp', [
    ])
    .controller('testctl',['$scope','$http','$q',function ($scope,$http,$q) {
    $scope.one = function () {
    $scope.file = $('#file').get(0).files[0];
    $scope.splitfilea(1);
    };

    $scope.splitfilea = function (currentpage) {
    let persize=1024*1024*10; //10Mb
    let allpage = Math.ceil($scope.file.size/persize);
    let start = (currentpage-1)*persize;
    let end = start+persize;
    if(currentpage===allpage){
    end=$scope.file.size;
    }
    $scope.filesplitdata = $scope.file.slice(start, end);
    $scope.r = new FileReader();
    $scope.r.readAsDataURL($scope.filesplitdata);
    $scope.r. onloadend=function (e) {
    console.log(currentpage);
    var bolb = e.target.result;
    $scope.encode_blob = new Blob([bolb]);//这里本来要加密,测试直接创建一个 Blob
    $q.when($scope.httppost($scope.encode_blob)).then(function () {
    delete $scope.formData;
    if(currentpage<=allpage){
    currentpage = currentpage+1;
    $scope.splitfilea(currentpage);
    }else{
    console.log('end');
    }
    });
    };
    };

    $scope.httppost = function (blob) {
    var deferral_local = $q.defer();
    $http({
    method: 'POST',
    url: '/test/up4/1.php',
    headers: {
    'Content-Type': undefined
    },
    data: {
    abc: blob,
    filename:"xxxxxxx.txt",
    type:"xxxxxx"
    },
    transformRequest: function (data, headersGetter) {
    if(!$scope.formData){
    $scope.formData = new FormData();
    }
    angular.forEach(data, function (value, key) {
    if(key === "abc"){
    $scope.formData.append(key, value,"xxx.txt");
    }else{
    $scope.formData.append(key, value);
    }
    });
    var headers = headersGetter();
    delete headers['Content-Type'];

    return $scope.formData;
    }
    }).success(function (response) {
    deferral_local.resolve( { status: 'good' } );
    });
    return deferral_local.promise;
    };

    }]);
    }());

    </script>

    </body>
    </html>


    服务端: 4.php(暂为空)
    <?php
    ?>

    这个上传 1G 左右大文件时会上传大约 40 个分片的时候就报错了.
    JS 小白,求大神指点, 估计应该还是 blob 大小限制, 一直不明白的就是我都分片了, 怎么还是超过限制呢?
    10 条回复    2017-03-23 14:45:44 +08:00
    nilai
        1
    nilai  
    OP
       2017-03-23 10:45:13 +08:00
    当然了, 在分片上传的时候,我使用了 FormData 上传文件,这样会上传更快些, 浏览器不卡, 如果是直接用 DATAURL 写在 POST data 中 这样浏览器会卡, 但是整个文件能上传完成。
    Mutoo
        2
    Mutoo  
       2017-03-23 11:56:21 +08:00
    fineuploader, 支持 blob ,支持分片。
    ykjsw
        3
    ykjsw  
       2017-03-23 12:00:28 +08:00
    http://www.plupload.com/
    用这个组件。
    donlxn22
        4
    donlxn22  
       2017-03-23 13:02:32 +08:00
    这个是 Chrome 的 Bug , Blob 不能正常的清除缓存导致报错,从 55 版本开始已经修好,升级 Chrome 版本。这里是这个问题官方的 Issue 修复记录:

    https://bugs.chromium.org/p/chromium/issues/detail?id=375297
    nilai
        5
    nilai  
    OP
       2017-03-23 13:40:46 +08:00
    @donlxn22 谢谢。 我去下最新的 chrome 来试试看。
    nilai
        6
    nilai  
    OP
       2017-03-23 14:13:16 +08:00
    代码没问题, 经测试,为 Chrome Bug 升级到最新版本,一切正常
    @donlxn22 感谢提醒。

    结帖
    cevincheung
        7
    cevincheung  
       2017-03-23 14:20:06 +08:00
    webuploader 、 plupload 这些支持分片上传的插件都有分片的前置操作回调,可以加密的。
    nilai
        8
    nilai  
    OP
       2017-03-23 14:30:31 +08:00
    @cevincheung 虽然我的问题解决了, 但是还是想了解一下 webuploader plupload 的分片的前置操作回调,必竞人家的更加成熟和稳定,麻烦能否写个小 DEMO , 我找了半天没找到,谢谢。
    cevincheung
        9
    cevincheung  
       2017-03-23 14:45:18 +08:00
    @nilai #8
    比如: http://www.plupload.com/docs/v2/Uploader#BeforeChunkUpload-event 事件名称: BeforeChunkUpload 可以获取到当前上传 chunk 的 blob 内容,然后进行加密处理。
    cevincheung
        10
    cevincheung  
       2017-03-23 14:45:44 +08:00
    服务端进行对每个 chunk 的解密存储就好了嘛。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2779 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 51ms · UTC 12:52 · PVG 20:52 · LAX 04:52 · JFK 07:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.