我正在尝试使用以下代码通过我的Web应用程序上传文件。
查看:
<form name="uploadForm" class="form-horizontal col-sm-12">
<div class="col-sm-4">
<input type="file" ng-model="rsdCtrl.viewData.file" name="file"/>
</div>
<div class="col-sm-4">
<button class="btn btn-success" type="submit" ng-click="uploadFile()">Upload</button>
</div>
</form>
控制器:
function uploadFile(){
if (uploadForm.file.$valid && file) {
return uploadService.upload(vd.file, "Convictions Calculator", "PCCS").then(function(response){
/* Some stuff */
}).catch(handleServiceError);
}
}
uploadService:
(function (){
'use strict';
angular.module('cica.common').service('uploadService', ['$http', '$routeParams', uploadService]);
function uploadService($http, $routeParams) {
this.upload = function (file, name, type) {
const fd = new FormData();
fd.append('document', file);
fd.append('jobId', $routeParams.jobId);
fd.append('documentRename', name);
fd.append('documentType', type);
return $http.post('/document/upload', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).catch(function(err){
handleHttpError('Unable to upload document.', err);
});
};
}
})();
routes.js:
'POST /document/upload': {controller: 'DocumentController', action: 'uploadDocument'},
DocumentController:
"use strict";
const fs = require('fs');
module.exports = {
uploadDocument: function (req, res) {
console.log(req.allParams()); //Inserted as part of debugging
const params = req.allParams();
req.file('document').upload({
// don't allow the total upload size to exceed ~100MB
maxBytes: 100000000
}, function whenDone(err, uploadedFiles) {
if (err) {
return res.serverError(err);
}
// If no files were uploaded, respond with an error.
else if (uploadedFiles.length === 0) {
return res.serverError('No file was uploaded');
} else {
const filePath = uploadedFiles[0].fd;
const filename = uploadedFiles[0].filename;
return fs.readFile(filePath, function (err, data) {
if (err) {
return res.serverError(err);
} else {
const jobId = params.jobId;
const jobVars =
{
filePath: results.filePath,
fileName: params.documentRename,
fileType: params.documentType
};
return DocumentService.uploadConvictions(req.session.sessionId, jobId, jobVars).then(function (response) {
return res.send("Document uploaded.");
}).catch(function (err) {
return res.serverError(err);
});
}
});
}
});
},
如果我上传一个.jpeg(大约11kB),则上传的效果与预期的一样,但是,如果我尝试上传一个更大的.jpeg(大约170kB),它就会掉下来。尽管没有立即引发/捕获的错误,但是发生的是在上载服务中创建的formData对象似乎丢失了其数据。如果我在其值上设置断点,则对于较大的文件它将返回空,当函数尝试进一步使用这些变量时,最终将导致错误。您可以通过这种方法上传的文件大小是否设置了某种限制,或者我配置不正确?
答案 0 :(得分:3)
我借此机会并假设您使用print (df)
No. timestamp letter
0 1 2018-07-07 00:15:52 A
1 2 2018-07-07 09:55:34 A
2 3 2018-07-07 14:13:32 A
3 4 2018-07-08 02:22:51 A
作为中间件。 bodyParser的默认bodyParser
为100kb。看limit
:
node_modules/body-parser/lib/types/urlencoded.js
您可以通过
更改var limit = typeof options.limit !== 'number'
? bytes(options.limit || '100kb')
: options.limit
中的限制
app.js
答案 1 :(得分:3)
我使用此替代方法...
HTML:
<input type="file" style="display:none" value="" id="uploadNewAttachment"/>
JavaScript:
在JavaScript中,您可以使用3种方法上传文件:
var binBlob = []; // If you use AngularJS, better leave it out of the DOM
var fi = document.getElementById('uploadNewAttachment');
fi.onchange = function(e) {
r = new FileReader();
r.onloadend = function(ev) {
binBlob[binBlob.length] = ev.target.result;
};
//r.readAsDataURL(e.target.files[0]); // Very slow due to Base64 encoding
//r.readAsBinaryString(e.target.files[0]); // Slow and may result in incompatible chars with AJAX and PHP side
r.readAsArrayBuffer(e.target.files[0]); // Fast and Furious!
};
$(fi).trigger('click');
我们拥有的JavaScript端是一个Uint8Array字节,其值从0到255(或Int8Array -128到127)。
通过AJAX发送此数组时,将使用符号和逗号将其“最大化”。这样会增加发送的总字节数。
EX:
[123, 38, 98, 240, 136, ...] or worse: [-123, 38, -81, 127, -127, ...]
如您所见,传输的字符数过大。
我们可以改为进行以下操作:
在通过AJAX发送数据之前,请执行以下操作:
var hexBlob = [];
for(var idx=0; idx<binBlob.length; idx++) {
var ex = Array.from(new Uint8Array(binBlob[idx]));;
for(var i=0;i<ex.length; i++) {
ex[i] = ex[i].toString(16).padStart(2,'0');
};
hexBlob[idx] = ex.join('');
}
您现在拥有的是一个用char组成的十六进制字节字符串!
例如:
3a05f4c9...
使用较少的带符号或无符号javascript数组的字符。
PHP: 在PHP方面,您只需使用以下命令即可将该数组直接解码为二进制数据:
for($idx=0; $idx<=count($hexBlob); $idx++) {
// ...
$binData = pack('H*',$hexBlob[$idx]);
$bytesWritten = file_put_contents($path.'/'.$fileName[$idx], $binData);
//...
}
此解决方案对我来说效果很好。
答案 2 :(得分:1)
FormData API用base64编码数据,这会增加33%的额外开销。
直接发送文件而不是发送FormData
:
app.service('fileUpload', function ($http) {
this.uploadFileToUrl = function (url, file) {
̶v̶a̶r̶ ̶f̶d̶ ̶=̶ ̶n̶e̶w̶ ̶F̶o̶r̶m̶D̶a̶t̶a̶(̶)̶;̶
̶f̶d̶.̶a̶p̶p̶e̶n̶d̶(̶'̶f̶i̶l̶e̶'̶,̶ ̶f̶i̶l̶e̶)̶;̶
̶r̶e̶t̶u̶r̶n̶ ̶$̶h̶t̶t̶p̶.̶p̶o̶s̶t̶(̶u̶r̶l̶,̶ ̶f̶d̶,̶ ̶{̶
return $http.post(url, file, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
});
};
});
浏览器发送FormData
时,它使用'Content-Type': multipart/formdata
并使用base64编码每个部分。
浏览器发送文件(或Blob)时,会将内容类型设置为文件(或Blob)的MIME类型。它将二进制数据放入请求的正文中。
<input type="file">
与ng-model
一起使用 2 现成的ng-model
指令不适用于input type="file"
。它需要一个指令:
app.directive("selectNgFile", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files[0];
ngModel.$setViewValue(files);
})
}
}
});
用法:
<input type="file" select-ng-file ng-model="rsdCtrl.viewData.file" name="file"/>