如何通过Meteor Iron Router从S3提供文件

时间:2014-03-19 19:02:40

标签: amazon-s3 meteor iron-router

我的问题与this one非常相似,它描述了如何使用Iron Router提供本地文件。我需要做同样的事情,但我不是从磁盘同步读取文件,而是需要从S3获取文件,这是一个异步调用。

问题似乎是action方法在异步s3.getObject完成之前返回的事实给出了以下错误。

Error: Can't render headers after they are sent to the client.

我假设Iron Router在我意识到我没有处理action方法中的响应时为我生成响应,但是我很难过如何告诉它等待我异步调用完成。

这是我的代码。

Router.map(function () {
    this.route('resumeDownload', {
        where: 'server',
        path: '/resume/:_id',
        action: function () {
            var response = this.response;

            var candidate = Candidates.findOne(this.params._id);
            if (!candidate || !candidate.resumeS3Key) {
                // this works fine because the method hasn't returned yet.
                response.writeHead(404);
                return response.end();
            }

            var s3 = new AWS.S3();
            s3.getObject({Bucket: 'myBucket', Key: candidate.resumeS3Key}, function (err, data) {
                if (err) {
                    // this will cause the error to be displayed
                    response.writeHead(500);
                    return response.end();
                }
                // this will also cause the error to be displayed
                response.writeHead(200, {'Content-Type': data.ContentType});
                response.end(data.Body);
            });
        }
    });
});

1 个答案:

答案 0 :(得分:4)

我能够自己解决这个问题。我需要在future方法中使用action

这是工作代码。

Router.map(function () {
    this.route('resumeDownload', {
        where: 'server',
        path: '/resume/:_id',
        action: function () {
            var response = this.response,
                candidate = Candidates.findOne(this.params._id);

            if (!candidate || !candidate.resumeS3Key) {
                response.writeHead(404);
                return response.end();
            }

            var Future = Npm.require('fibers/future'),
                s3 = new AWS.S3(),
                futureGetObject = Future.wrap(s3.getObject.bind(s3)),
                data = futureGetObject({Bucket: 'myBucket', Key: candidate.resumeS3Key}).wait();

            response.writeHead(200, {'Content-Type': data.ContentType});
            response.end(data.Body);
        }
    });
});