NodeJS

2015-01-19 14 views
37

के साथ अमेज़ॅन S3 पर एक फ़ाइल अपलोड करें I S3 बाल्टी में फ़ाइल अपलोड करने का प्रयास करते समय एक समस्या में भाग गया। सबकुछ काम करता है सिवाय इसके कि मेरी फ़ाइल पैरामीटर उचित प्रतीत नहीं होते हैं। मैं नोडजेस से एस 3 तक अपलोड करने के लिए अमेज़ॅन एस 3 एसडीके का उपयोग कर रहा हूं।NodeJS

var multiparty = require('connect-multiparty'), 
    multipartyMiddleware = multiparty(); 
app.route('/api/items/upload').post(multipartyMiddleware, items.upload); 

यह items.upload() फ़ंक्शन है:

exports.upload = function(req, res) { 
    var file = req.files.file; 
    var s3bucket = new AWS.S3({params: {Bucket: 'mybucketname'}}); 
    s3bucket.createBucket(function() { 
     var params = { 
      Key: file.name, 
      Body: file 
     }; 
     s3bucket.upload(params, function(err, data) { 
      console.log("PRINT FILE:", file); 
      if (err) { 
       console.log('ERROR MSG: ', err); 
      } else { 
       console.log('Successfully uploaded data'); 
      } 
     }); 
    }); 
}; 

"hello" की तरह एक स्ट्रिंग के लिए Body परम स्थापना ठीक काम करता है

ये मेरी मार्गों सेटिंग नहीं है। doc के अनुसार, Body परम को (बफर, टाइप किया हुआ ऐरे, ब्लॉब, स्ट्रिंग, रीडेबलस्ट्रीम) ऑब्जेक्ट डेटा लेना चाहिए। हालांकि, एक फ़ाइल वस्तु को अपलोड निम्न त्रुटि संदेश के साथ विफल:

{ fieldName: 'file', 
    originalFilename: 'second_fnp.png', 
    path: '/var/folders/ps/l8lvygws0w93trqz7yj1t5sr0000gn/T/26374-7ttwvc.png', 
    headers: 
    { 'content-disposition': 'form-data; name="file"; filename="second_fnp.png"', 
    'content-type': 'image/png' }, 
    ws: 
    { _writableState: 
     { highWaterMark: 16384, 
     objectMode: false, 
     needDrain: true, 
     ending: true, 
     ended: true, 
     finished: true, 
     decodeStrings: true, 
     defaultEncoding: 'utf8', 
     length: 0, 
     writing: false, 
     sync: false, 
     bufferProcessing: false, 
     onwrite: [Function], 
     writecb: null, 
     writelen: 0, 
     buffer: [], 
     errorEmitted: false }, 
    writable: true, 
    domain: null, 
    _events: { error: [Object], close: [Object] }, 
    _maxListeners: 10, 
    path: '/var/folders/ps/l8lvygws0w93trqz7yj1t5sr0000gn/T/26374-7ttwvc.png', 
    fd: null, 
    flags: 'w', 
    mode: 438, 
    start: undefined, 
    pos: undefined, 
    bytesWritten: 261937, 
    closed: true }, 
    size: 261937, 
    name: 'second_fnp.png', 
    type: 'image/png' } 

किसी भी मदद की बहुत सराहना की जाएगी:

[Error: Unsupported body payload object] 

इस फ़ाइल में वस्तु है!

+0

आपके सर्वर केवल S3-साइन्ड-यूआरएल बनाने के लिए एडब्ल्यूएस रहस्य स्टोर करने के लिए (की जरूरत है aws-sdk का उपयोग कर)। ग्राहक हस्ताक्षरित यूआरएल पुनर्प्राप्त करता है, उस यूआरएल का उपयोग करते हुए कोई भी अपलोड क्लाइंट-साइड होता है। इस मार्गदर्शिका को चेकआउट करें: https://devcenter.heroku.com/articles/s3-upload-node – rocketspacer

उत्तर

63

तो ऐसा लगता है कि यहां कुछ चीज़ें गलत हो रही हैं। आपकी पोस्ट के आधार पर ऐसा लगता है कि आप connect-multiparty मिडलवेयर का उपयोग करके फ़ाइल अपलोड का समर्थन करने का प्रयास कर रहे हैं। यह मिडलवेयर क्या करता है अपलोड की गई फ़ाइल लेता है, इसे स्थानीय फाइल सिस्टम पर लिखें और फिर अपलोड की गई फाइलों में req.files सेट करें।

आपके मार्ग की कॉन्फ़िगरेशन ठीक दिखती है, समस्या आपके items.upload() फ़ंक्शन के साथ दिखती है। इस भाग के साथ विशेष रूप से:

var params = { 
    Key: file.name, 
    Body: file 
}; 

मैं अपने जवाब connect-multiparty की शुरुआत में उल्लेख किया है स्थानीय फाइल सिस्टम के लिए फ़ाइल लिखते हैं, तो आप फिर फ़ाइल को खोलने के लिए और इसे पढ़ा, फिर अपलोड यह आवश्यकता होगी, और इसे स्थानीय फाइल सिस्टम पर हटा दें।

कहा है कि आप की तरह निम्नलिखित कुछ करने के लिए अपने विधि को अपडेट कर सकते हैं:

var fs = require('fs'); 
exports.upload = function (req, res) { 
    var file = req.files.file; 
    fs.readFile(file.path, function (err, data) { 
     if (err) throw err; // Something went wrong! 
     var s3bucket = new AWS.S3({params: {Bucket: 'mybucketname'}}); 
     s3bucket.createBucket(function() { 
      var params = { 
       Key: file.originalFilename, //file.name doesn't exist as a property 
       Body: data 
      }; 
      s3bucket.upload(params, function (err, data) { 
       // Whether there is an error or not, delete the temp file 
       fs.unlink(file.path, function (err) { 
        if (err) { 
         console.error(err); 
        } 
        console.log('Temp File Delete'); 
       }); 

       console.log("PRINT FILE:", file); 
       if (err) { 
        console.log('ERROR MSG: ', err); 
        res.status(500).send(err); 
       } else { 
        console.log('Successfully uploaded data'); 
        res.status(200).end(); 
       } 
      }); 
     }); 
    }); 
}; 

यह क्या करता है स्थानीय फाइल सिस्टम से अपलोड की गई फ़ाइल पढ़ी जाती है, तो एस 3 के लिए इसे अपलोड कर देती है, तो यह अस्थायी फ़ाइल को हटा देता है और एक प्रतिक्रिया भेजता है।

इस दृष्टिकोण के साथ कुछ समस्याएं हैं। सबसे पहले, यह उतना कुशल नहीं है जितना हो सकता है, क्योंकि बड़ी फाइलों के लिए आप इसे लिखने से पहले पूरी फाइल लोड कर देंगे। दूसरा, यह प्रक्रिया बड़ी फ़ाइलों के लिए बहु-भाग अपलोड का समर्थन नहीं करती है (मुझे लगता है कि बहु-भाग अपलोड करने से पहले कट-ऑफ 5 एमबी है)।

इसके बजाय मैं क्या सुझाव दूंगा कि आप S3FS नामक एक मॉड्यूल का उपयोग कर रहे हैं जो नोड.जेएस में देशी FS पर एक समान इंटरफेस प्रदान करता है लेकिन बहु-भाग अपलोड जैसे कुछ विवरणों को सार तत्वों को हटा देता है और एस 3 एपीआई (साथ ही रिकर्सिव विधियों जैसे कुछ अतिरिक्त कार्यक्षमता भी जोड़ता है)।

आप S3FS पुस्तकालय में खींचने के लिए थे, तो आपके कोड कुछ इस तरह दिखेगा:

var fs = require('fs'), 
    S3FS = require('s3fs'), 
    s3fsImpl = new S3FS('mybucketname', { 
     accessKeyId: XXXXXXXXXXX, 
     secretAccessKey: XXXXXXXXXXXXXXXXX 
    }); 

// Create our bucket if it doesn't exist 
s3fsImpl.create(); 

exports.upload = function (req, res) { 
    var file = req.files.file; 
    var stream = fs.createReadStream(file.path); 
    return s3fsImpl.writeFile(file.originalFilename, stream).then(function() { 
     fs.unlink(file.path, function (err) { 
      if (err) { 
       console.error(err); 
      } 
     }); 
     res.status(200).end(); 
    }); 
}; 

क्या यह कर देगा प्रदान की बाल्टी और AWS क्रेडेंशियल के मॉड्यूल का दृष्टांत और फिर बाल्टी अगर इसे बनाने है अस्तित्व में नहीं है फिर जब कोई फ़ाइल अपलोड करने के लिए कोई अनुरोध आता है तो हम फ़ाइल में एक स्ट्रीम खोलेंगे और फ़ाइल को S3 पर निर्दिष्ट पथ पर लिखने के लिए उपयोग करेंगे। यह दृश्यों के पीछे बहु-भाग अपलोड टुकड़ा को संभालेगा (यदि आवश्यक हो) और स्ट्रीम के माध्यम से होने का लाभ है, तो आपको इसे अपलोड करना शुरू करने से पहले पूरी फ़ाइल को पढ़ने के लिए इंतजार नहीं करना पड़ेगा।

यदि आप चाहें, तो आप कोड को Promises से कॉलबैक में बदल सकते हैं। या ईवेंट श्रोता के साथ अंत/त्रुटियों को निर्धारित करने के लिए pipe() विधि का उपयोग करें।

यदि आप कुछ अतिरिक्त तरीकों की तलाश में हैं, तो s3fs के लिए प्रलेखन देखें और यदि आप कुछ अतिरिक्त तरीकों की तलाश कर रहे हैं या समस्याएं हैं तो कोई समस्या खोलने के लिए स्वतंत्र महसूस करें।

+11

आपको यह सोचने के लिए खेद है कि मैं कठोर हूं। अफसोस की बात है, यह वह नहीं था जिसने संपादन को खारिज कर दिया, यह समुदाय था। तो मैंने खुद को संपादित किया है कि वास्तव में यह सही कोड को दर्शाता है। चियर्स मैन! – David

+2

मेरे पास एक बाल्टी और एक फ़ोल्डर है। मैं इस फ़ोल्डर में अपलोड होने वाली ऑब्जेक्ट को ACL निर्दिष्ट कैसे कर सकता हूं। मैंने फ़ोल्डर अनुमतियों को "सार्वजनिक बनाएं" में बदल दिया है, लेकिन जब भी कोई नई वस्तु अपलोड की जाती है तो यह सार्वजनिक नहीं होती है। मैंने एसीएल की कोशिश की: एस 3 एफएस कन्स्ट्रक्टर के भीतर "पब्लिक-रीड" लेकिन यह काम नहीं करता है। – Dan

+0

यदि आप ऑब्जेक्ट लिखने के लिए S3FS का उपयोग कर रहे हैं तो आप एसीएल निर्दिष्ट कर सकते हैं। इस लिंक को जांचें: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property अन्यथा आपको S3FS के बाहर फ़ाइल अपलोड करते समय नीति निर्दिष्ट करने की आवश्यकता होगी। – David

5

मैं एक काम कर समाधान ::

npm install aws-sdk 


एक बार जब आप एडब्ल्यूएस-sdk स्थापित किया है, अपने जहां जरूरत के साथ निम्नलिखित कोड मूल्यों की जगह का उपयोग होने के लिए निम्नलिखित पाया।

var AWS = require('aws-sdk'); 
var fs = require('fs'); 

var s3 = new AWS.S3(); 

// Bucket names must be unique across all S3 users 

var myBucket = 'njera'; 

var myKey = 'jpeg'; 
//for text file 
//fs.readFile('demo.txt', function (err, data) { 
//for Video file 
//fs.readFile('demo.avi', function (err, data) { 
//for image file     
fs.readFile('demo.jpg', function (err, data) { 
    if (err) { throw err; } 



    params = {Bucket: myBucket, Key: myKey, Body: data }; 

    s3.putObject(params, function(err, data) { 

     if (err) { 

      console.log(err) 

     } else { 

      console.log("Successfully uploaded data to myBucket/myKey"); 

     } 

     }); 

}); 

मैं विषय के मामले में यहां पर पूरा ट्यूटोरियल पाया आप संदर्भ के लिए देख रहे हैं ::


How to upload files (text/image/video) in amazon s3 using node.js