文件名未用作AWS S3名称

时间:2014-11-06 18:24:41

标签: javascript node.js amazon-web-services express

我正在使用expressjs并尝试将图像POST到AWS S3,可以在我的应用程序中使用。我一直关注这个tutorial,虽然我能够成功上传图片,但每次都会给出default_name的文件名,我不相信文件格式是附加到string为文件提供正确的图像格式。当我查看教程中提供的s3upload.js脚本时,我注意到default_name是它们为文件提供的标准名称,但我不确定为什么它在不使用它的情况下接受我的文件标题。

events-create.ejs(我上传的地方):

<!DOCTYPE HTML>
<html>
<head>
    <% include ../partials/head %>
</head>

<body>
    <% include ../partials/navigation %>


<div class="grid" id="create-event-container">
        <div class="col-1-1">
            <div id="create-event">
                <h1><i>Create Event</i></h1>
                <input type="file" id="files"/>

                <p id="status">Please select a file</p>
                <div id="preview"><img src="/images/event-placeholder.png"></div>
                <form action="/admin/events/create" method="POST">
                    <input type="hidden" id="speaker-image" name="speakerImage" value="/images/event-placeholder.png" />
                    Name: <input type="text" name="name"><br>
                    Title: <input type="text" name="title"><br>
                    Company: <input type="text" name="company"><br>
                    Website: <input type="text" name="url"><br>
                    <input type="submit" value="Submit"><br>
                </form>
            </div>
        </div>
    </div>

    <script type="text/javascript" src="/js/s3upload.js" async></script>

    <script>
        console.log("S3 Function Launched");

        function s3_upload(){
            var status_elem = document.getElementById("status");
            var url_elem = document.getElementById("speaker-image");
            var preview_elem = document.getElementById("preview");
            var s3upload = new S3Upload({
                file_dom_selector: 'files',
                s3_sign_put_url: '/sign_s3',
                onProgress: function(percent, message) {
                    status_elem.innerHTML = 'Upload progress: ' + percent + '% ' + message;
                },
                onFinishS3Put: function(public_url) {
                    status_elem.innerHTML = 'Upload completed. Uploaded to: '+ public_url;
                    url_elem.value = public_url;
                    console.log(public_url);
                    preview_elem.innerHTML = '<img src="'+public_url+'" style="width:300px;" />';
                },
                onError: function(status) {
                    status_elem.innerHTML = 'Upload error: ' + status;
                    console.log(status_elem.innerHTML);
                }
            });
        }
        /*
        * Listen for file selection:
        */
        (function() {

            var input_element = document.getElementById("files");
            input_element.onchange = s3_upload;
        })();
    </script>

</body>
</html>

routes.js:

var express = require('express');
var router = express.Router();
var Event = require('./models/eventsModel');
var http = require('http');
var path = require('path');
var aws = require('aws-sdk');

var AWS_ACCESS_KEY = process.env.AWS_ACCESS_KEY;
var AWS_SECRET_KEY = process.env.AWS_SECRET_KEY;
var S3_BUCKET = process.env.S3_BUCKET;


    router.get('/sign_s3', function(req, res){
        aws.config.update({accessKeyId: AWS_ACCESS_KEY, secretAccessKey: AWS_SECRET_KEY });
        var s3 = new aws.S3();
        var s3_params = {
            Bucket: S3_BUCKET,
            Key: req.query.s3_object_name,
            Expires: 60,
            ContentType: req.query.s3_object_type,
            ACL: 'public-read'
        };
        s3.getSignedUrl('putObject', s3_params, function(err, data){
            if(err){
                console.log(err);
            }
            else{
                var return_data = {
                    signed_request: data,
                    url: 'https://'+S3_BUCKET+'.s3.amazonaws.com/'+req.query.s3_object_name
                };
                res.write(JSON.stringify(return_data));
                res.end();
            }
        });
    });

    router.route('/admin/events/create')

        .post(function(req, res){

            var events = new Event();

            events.name = req.body.name;
            events.title = req.body.title;
            events.company = req.body.company;
            events.url = req.body.url;
            events.speakerImage = req.body.url;

            events.save(function(err){
                if (err)
                    res.send(err);

                res.redirect(303, '/events');

            });
        })

        .get(function(req, res){
            Event.find(function(err, events){
                if (err)
                    res.send(err);

                res.render('pages/events-create.ejs');
            });
        });

s3upload.js:

(function() {

  window.S3Upload = (function() {

    S3Upload.prototype.s3_object_name = 'default_name';

    S3Upload.prototype.s3_sign_put_url = '/signS3put';

    S3Upload.prototype.file_dom_selector = 'file_upload';

    S3Upload.prototype.onFinishS3Put = function(public_url) {
      return console.log('base.onFinishS3Put()', public_url);
    };

    S3Upload.prototype.onProgress = function(percent, status) {
      return console.log('base.onProgress()', percent, status);
    };

    S3Upload.prototype.onError = function(status) {
      return console.log('base.onError()', status);
    };

    function S3Upload(options) {
      if (options == null) options = {};
      for (option in options) {
        this[option] = options[option];
      }
      this.handleFileSelect(document.getElementById(this.file_dom_selector));
    }

    S3Upload.prototype.handleFileSelect = function(file_element) {
      var f, files, output, _i, _len, _results;
      this.onProgress(0, 'Upload started.');
      files = file_element.files;
      output = [];
      _results = [];
      for (_i = 0, _len = files.length; _i < _len; _i++) {
        f = files[_i];
        _results.push(this.uploadFile(f));
      }
      return _results;
    };

    S3Upload.prototype.createCORSRequest = function(method, url) {
      var xhr;
      xhr = new XMLHttpRequest();
      if (xhr.withCredentials != null) {
        xhr.open(method, url, true);
      } else if (typeof XDomainRequest !== "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
      } else {
        xhr = null;
      }
      return xhr;
    };

    S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
      var this_s3upload, xhr;
      this_s3upload = this;
      xhr = new XMLHttpRequest();
      xhr.open('GET', this.s3_sign_put_url + '?s3_object_type=' + file.type + '&s3_object_name=' + this.s3_object_name, true);
      xhr.overrideMimeType('text/plain; charset=x-user-defined');
      xhr.onreadystatechange = function(e) {
        var result;
        if (this.readyState === 4 && this.status === 200) {
          try {
            result = JSON.parse(this.responseText);
          } catch (error) {
            this_s3upload.onError('Signing server returned some ugly/empty JSON: "' + this.responseText + '"');
            return false;
          }
          return callback(result.signed_request, result.url);
        } else if (this.readyState === 4 && this.status !== 200) {
          return this_s3upload.onError('Could not contact request signing server. Status = ' + this.status);
        }
      };
      return xhr.send();
    };

    S3Upload.prototype.uploadToS3 = function(file, url, public_url) {
      var this_s3upload, xhr;
      this_s3upload = this;
      xhr = this.createCORSRequest('PUT', url);
      if (!xhr) {
        this.onError('CORS not supported');
      } else {
        xhr.onload = function() {
          if (xhr.status === 200) {
            this_s3upload.onProgress(100, 'Upload completed.');
            return this_s3upload.onFinishS3Put(public_url);
          } else {
            return this_s3upload.onError('Upload error: ' + xhr.status);
          }
        };
        xhr.onerror = function() {
          return this_s3upload.onError('XHR error.');
        };
        xhr.upload.onprogress = function(e) {
          var percentLoaded;
          if (e.lengthComputable) {
            percentLoaded = Math.round((e.loaded / e.total) * 100);
            return this_s3upload.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
          }
        };
      }
      xhr.setRequestHeader('Content-Type', file.type);
      xhr.setRequestHeader('x-amz-acl', 'public-read');
      return xhr.send(file);
    };

    S3Upload.prototype.uploadFile = function(file) {
      var this_s3upload;
      this_s3upload = this;
      return this.executeOnSignedUrl(file, function(signedURL, publicURL) {
        return this_s3upload.uploadToS3(file, signedURL, publicURL);
      });
    };

    return S3Upload;

  })();

}).call(this);

2 个答案:

答案 0 :(得分:1)

您可以在客户端或服务器端设置文件名。

客户端:在events-create.ejs中,将此参数传递给S3Upload:

s3_object_name: $('input[type=file]').val().match(/[^\/\\]+$/)[0]

服务器端(首选方法):在routes.js中,用{em>唯一文件名替换req.query.s3_object_name的所有实例。您可以使用req.query.s3_object_type来确定应放在文件名末尾的扩展名。您希望在此使用唯一的文件名,因为所有文件都存储在同一个存储桶中,AWS会自动覆盖具有相同文件名的文件。

答案 1 :(得分:0)

我遇到了同样的问题,这就是我在节点控制器中解决它的方法:

aws.config.update({accessKeyId: AWS_ACCESS_KEY, secretAccessKey: AWS_SECRET_KEY});
    var s3 = new aws.S3();

    // Set Extension
    switch(req.query.s3_object_type) {
        case 'image/png': 
            var ext = '.png';
        break;
        case 'image/gif':
            var ext = '.gif';
        break;
        case 'image/jpg': 
        case 'image/jpeg':
            var ext = '.jpg';
        break;
    }

    // Rename File
    var name = Math.floor(new Date() / 1000);

    // Set S3
    var s3_params = {
        Bucket: S3_BUCKET,
        Key: 'blog/'+name+ext,
        Expires: 60,
        ContentType: req.query.s3_object_type,
        ACL: 'public-read'
    };

    // Send S3
    s3.getSignedUrl('putObject', s3_params, function(err, data){
        if(err){
            console.log(err);
        }
        else{
            var return_data = {
                signed_request: data,
                url:   'https://'+S3_BUCKET+'.s3.amazonaws.com/'+name+ext
            };
            res.write(JSON.stringify(return_data));
            res.end();
        }
    });

因为您可以看到一个非常简单的问题解决方案,只需检查扩展名并重命名该文件即可。希望这会有所帮助。