【问题标题】:Download image from skipper-gridfs in Sails.js从 Sails.js 中的 skipper-gridfs 下载图像
【发布时间】:2015-03-07 02:06:11
【问题描述】:

我在sails.js 应用程序中使用gridfs 将图像上传到服务器。我的上传代码如下

upload: function  (req, res) {
        req.file('avatar')
            .upload({
                adapter: require('skipper-gridfs'),
                uri: 'mongodb://localhost:27017/dbname.images'
            }, function whenDone(err, uploadedFiles) {
                if (err) return res.negotiate(err);
                else return res.ok({
                    files: uploadedFiles,
                    textParams: req.params.all()
                });
            });
    }

我从这里得到以下响应...

{
    "files": [
        {
            "fd": "2d8910a0-8ca2-4df1-9930-6ddd721a0416.jpg",
            "size": 172883,
            "type": "image/jpeg",
            "filename": "Photo on 12-20-14 at 9.53 PM.jpg",
            "status": "bufferingOrWriting",
            "field": "avatar",
            "extra": {
                "fileId": "54aee6ced4a0e88f0dc9025f",
                "fd": "2d8910a0-8ca2-4df1-9930-6ddd721a0416.jpg",
                "dirname": "."
            }
        }
    ],
    "textParams": {}
}

我的问题是,如果我需要下载上面上传的文件,我该怎么办?我在互联网上获得了以下用于下载任务的代码,但这对我来说没有多大意义。基本上我想要上传图片的下载网址,我可以在移动应用中使用该网址来显示图片。

var blobAdapter = require('skipper-gridfs')({
            uri: 'mongodb://localhost:27017/dbname.images'
        });
        blobAdapter.read(filename, callback);

有人可以帮我吗?提前致谢。

【问题讨论】:

    标签: javascript node.js mongodb sails.js gridfs


    【解决方案1】:

    经过一番研究,我终于设法解决了这个问题。我在文件上传后的响应中得到字段 fd 并将其保存以供以后使用。我去了skipper-gridfs 代码并找到了一个'read' 方法,它接受该值并返回所需的文件。因此,我只是通过该方法从 mongo 中提取了该文件并作为响应发送。这是工作文件。

    download: function (req, res) {
            var blobAdapter = require('skipper-gridfs')({
                uri: 'mongodb://localhost:27017/mydbname.images'
            });
    
            var fd = req.param('fd'); // value of fd comes here from get request
            blobAdapter.read(fd, function(error , file) {
                if(error) {
                    res.json(error);
                } else {
                    res.contentType('image/png');
                    res.send(new Buffer(file));
                }
            });
        }
    

    希望以后能帮到像我这样的人:)

    【讨论】:

    • 感谢分享——这正是正确的做法。
    • 非常感谢!很高兴看到 Sails.JS 的创建者在这里感谢我的努力 :)
    • 我想知道在res.send() 中创建一个新缓冲区是否重要/有必要,因为concat-stream(skipper-gridfs 使用)返回二进制数据的缓冲区?
    • 是否可以使res.contentType('image/png'); 动态传递任何文件类型(PDF、xls、.doc 等)? @mikermcneil
    • @Ayon @Robert Rossmann 对不起,伙计们,我应该更清楚一点——我最初没有看到示例的结尾。我建议使用流式方法,而不是在下载时将整个文件加载到内存中。 (即省略 cb)因此,您可以使用 var gushingStream = blobAdapter.read(fd); return gushingStream.pipe(res); 代替回调函数。 >
    【解决方案2】:

    为了补充上面 Ayon 的出色回答,下面是演示流、持久文件元数据、动态内容类型和其他几个相关 cmets 的相同代码版本:

    download: function (req, res) {
    
      if (!_.isString(req.param('fileId') && !_.isNumber(req.param('fileId')){
        return res.badRequest('`fileId` should be provided as a string/number (depending on whether this is Mongo or MySQL, if you\'ve customized the primary key, etc.).');
      }
    
      // Look up file metadata
      UploadedFile.findOne({ id: req.param('fileId') })
      .exec(function (err, fileRecord) {
        if (err) { return res.serverError(err); }
        if (!fileRecord) { return res.notFound(); }
    
        // Get configured blob adapter instance.
        var blobAdapterOpts = _.omit(sails.config.fileUploads, 'adapter');
        var configuredBlobAdapter = sails.config.fileUploads.adapter(blobAdapterOpts);
    
        // Now locate the actual raw contents of the file using the
        // `fd` that we saved elsewhere (i.e. when uploading), and then
        // use the blob adapter to open up a stream of bytes (the file's
        // contents) and pipe that down as the HTTP response body.  
        // (like skipping a rock across the surface of a pond)
        var fileStream = configuredBlobAdapter.read(fileRecord.fd);
        fileStream.on('error', function (err){
          return res.serverError(err);
        });
    
        // Along the way, set the content-type for the response based on
        // whatever we saved when this file was originally uploaded.
        // 
        // (You could do the same thing for the filename, assuming this
        // file download is the "save as" kind, as determined by the
        // content-disposition header.)
        res.contentType(fileRecord.contentType);
    
        // Pipe the stream of file data through as our HTTP response body.
        // (like skipping a rock on the surface of a pond)
        return fileStream.pipe(res);
    
      });
    
    }
    

    为什么是流?

    这种流式传输方法使我们免于将整个文件加载到 我们服务器上的内存(这将成为其他问题时 处理大文件或许多并发下载)

    错误处理程序

    因为我们正在处理用户空间中的原始节点流/发射器 代码在这里,我们必须确保绑定一个“错误”事件处理程序 在做任何事情之前——以防万一。 (这可以防止任何 导致进程崩溃的意外流错误。)

    “打开”与“另存为”

    您可以使用请求参数作为标志来确定如何 设置 content-disposition 标头 - 因此是否 用户的浏览器/设备/本机应用程序应该“打开”与“另存为” 文件。

    自定义配置

    此示例演示了设置一些自定义配置。 例如在 config/custom.js 中,您可以输入: 模块.exports.custom = { 文件上传:{ 适配器:需要('skipper-fs'), uri: 'mongodb://localhost:27017/mydbname.images' }, };

    action2 呢?

    如果你正在使用actions2(在Sails v1.x 和更高版本中可用),你可以完成与res.pipe() 相同的事情~~以及相关的错误处理~~ 只需将流直接传递给exits.success()编辑:实际上,我对第二部分的看法是错误的——只是 verified 仍然必须自己处理 .on('error',...)。) 另外,你会还是要设置内容类型响应头;即env.res.contentType(fileRecord.contentType)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-08
      • 2012-01-30
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 2015-07-13
      • 2014-12-05
      • 2015-07-14
      相关资源
      最近更新 更多