javascript 上传大文件问题

2017-03-23 10:42:05 +08:00
 nilai
本地环境 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 大小限制, 一直不明白的就是我都分片了, 怎么还是超过限制呢?
3309 次点击
所在节点    JavaScript
10 条回复
nilai
2017-03-23 10:45:13 +08:00
当然了, 在分片上传的时候,我使用了 FormData 上传文件,这样会上传更快些, 浏览器不卡, 如果是直接用 DATAURL 写在 POST data 中 这样浏览器会卡, 但是整个文件能上传完成。
Mutoo
2017-03-23 11:56:21 +08:00
fineuploader, 支持 blob ,支持分片。
ykjsw
2017-03-23 12:00:28 +08:00
http://www.plupload.com/
用这个组件。
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
2017-03-23 13:40:46 +08:00
@donlxn22 谢谢。 我去下最新的 chrome 来试试看。
nilai
2017-03-23 14:13:16 +08:00
代码没问题, 经测试,为 Chrome Bug 升级到最新版本,一切正常
@donlxn22 感谢提醒。

结帖
cevincheung
2017-03-23 14:20:06 +08:00
webuploader 、 plupload 这些支持分片上传的插件都有分片的前置操作回调,可以加密的。
nilai
2017-03-23 14:30:31 +08:00
@cevincheung 虽然我的问题解决了, 但是还是想了解一下 webuploader plupload 的分片的前置操作回调,必竞人家的更加成熟和稳定,麻烦能否写个小 DEMO , 我找了半天没找到,谢谢。
cevincheung
2017-03-23 14:45:18 +08:00
@nilai #8
比如: http://www.plupload.com/docs/v2/Uploader#BeforeChunkUpload-event 事件名称: BeforeChunkUpload 可以获取到当前上传 chunk 的 blob 内容,然后进行加密处理。
cevincheung
2017-03-23 14:45:44 +08:00
服务端进行对每个 chunk 的解密存储就好了嘛。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/349660

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX