如何使用AngularJS上传文件并在ExpressJS中保存?

3

我正在使用AngularJS的指令angular-file-upload。我已经设置好并成功上传图片,但是似乎无法将文件解析到服务器端(express js)。

Jade:

input.form-input(ng-model="userAvatarFile" ng-file-select="onFileSelect($files)" name="userAvatarFile" type="file")

这是AngularJS的代码:
$scope.onFileSelect = function($files) {

    console.log($files);

    for (var i = 0; i < $files.length; i++) {
        var file = $files[i];
        $scope.upload = $upload.upload({
            url: '/api/user/upload', 
            method: 'POST',
            data: {myObj: $scope.userAvatarFile},
            file: file, 
        }).progress(function(evt) {
            console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
        }).success(function(data, status, headers, config) {
            console.log(data);
        });
    }
};

并且表达:

exports.upload = function(req, res) {
  console.log(req.body);
  console.log(req.files);
};

控制台始终打印出以下内容以供Express使用:
 {}
 undefined

有什么想法可能出了问题吗?


upload()函数是一个异步函数..你可以像这样在循环内部使用它,你必须发送数组中的所有文件并保存。 - Muhammad Ali
我不太明白你想表达什么,能否换个说法? - user3048402
2个回答

1

tgkokk's的Cloudinary示例在使用Cloudinary v1.1.1后已经失效。 Cloudinary更新了upload_stream方法来返回一个Transform流对象,因此请使用'pipe'代替手动添加'on(data)'和'on(end)'事件。

https://github.com/cloudinary/cloudinary_npm#version-11-upload_stream-change-notes

exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        var stream = cloudinary.uploader.upload_stream(function(result) {    console.log(result); 
        });

        // pipe can be used now
        file.pipe(stream);
    });
};

1

多部分中间件已在Connect 3.0中删除。 Connect建议使用connect-multipartyconnect-busboy。我的意见是connect-busboy更好,所以以下是如何操作:

(当然,运行npm install --save connect-busboy)

// Main file, stays the same for all the other examples
var express = require('express'),
    busboy  = require('connect-busboy');

app.use(busboy({ immediate: true }));

// Route file
exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        // fieldname will be 'file', file will be... um... the file (in binary encoding), filename will be the file's name
    });
    req.busboy.on('field', function (key, value) {
        // key will be 'myObj', value will be $scope.userAvatarFile
    });
};

如果您想将图像保存到文件中,可以执行以下操作:
exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        // saveTo is the temporary path
        var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
        file.pipe(fs.createWriteStream(saveTo));

        // Do stuff with saveTo
    });
};

然而,这是一种安全风险(将文件保存到磁盘,这就是为什么req.files不再存在的原因),因此大多数(?)与文件相关的库(例如Cloudinary)提供了一个WriteStream(或类似的东西)。以下是使用Cloudinary的方法:
exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        var stream = cloudinary.uploader.upload_stream(function(result) { console.log(result); });

        // You should have been able to do file.pipe(stream), but Cloudinary's stream isn't a real WriteStream, but just an object with two functions. Well, the following works too:

        file.on('data', stream.write);
        file.on('end', stream.end);
    });
};

就我个人而言,我复制了你的代码并测试过,它完全正常。如果你有任何问题,请告诉我。一周前我也遇到了同样的问题,所以我研究了一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接