Question

Image upload from Vue/Express to Spaces

Posted July 3, 2018 4.7k views
Development

I’m trying to upload a file from Vue/Express app to my DigitalOcean space, but I am having issues.

I worked through this tutorial, but in this example they are just using Express and I can’t submit the form data the way it is done in this tutorial.
https://www.digitalocean.com/community/tutorials/how-to-upload-a-file-to-object-storage-with-node-js

So, I continued playing around with it.

Here is the Vue part:

<template>
  <div>
    <h1>Upload a file</h1>

    <label>File
        <input type="file" id="file" ref="file" name="file" v-on:change="handleFileUpload()"/>
      </label>
        <button v-on:click="submitFile()">Submit</button>
</div>

</template>


<script>
import axios from "axios";
export default {
  data() {
    return {
      file: ""
    };
  },

  methods: {
    submitFile() {
      // Initialize the form data
      let formData = new FormData();
      // Add the form data we need to submit
      formData.append("file", this.file);
      // Make the request to the POST /single-file URL
      axios
        .post("/upload", file, {
          baseURL: "http://localhost:8000/"
          // headers: {
          //   "Content-Type": "multipart/form-data"
          // }
        })
        .then(function() {
          console.log("SUCCESS!!");
        })
        .catch(function() {
          console.log("FAILURE!!");
        });
    },
    // Handles a change on the file upload
    handleFileUpload() {
      this.file = this.$refs.file.files[0];
    }
  }
};
</script>
code

And in express I have my route:

const Uploads = require("./controllers/Uploads");

module.exports = app => {
  app.post("/upload", Uploads.index);
};

code

And within the controller I have:

// Load dependencies for file uploading to DO
const aws = require("aws-sdk");
const multer = require("multer");
const multerS3 = require("multer-s3");

// Set S3 endpoint to DigitalOcean Spaces
const spacesEndpoint = new aws.Endpoint("nyc3.digitaloceanspaces.com");
const s3 = new aws.S3({
  endpoint: spacesEndpoint
});

// Image upload middleware
// Change bucket property to your Space name
const upload = multer({
  storage: multerS3({
    s3: s3,
    bucket: "1410",
    acl: "public-read",
    key: function(request, file, cb) {
      console.log(file);
      cb(null, file.originalname);
    }
  })
}).array("upload", 1);

module.exports = {
  index(req, res) {
    console.log("backend hit");
    upload(req, res, function(error) {
      if (error) {
        console.log(error);
        return res.redirect("/error");
      }
      console.log("File uploaded successfully.");
      res.redirect("/success");
    });
  }
};

code

When I upload the image I actually get the “File uploaded successfully” message, but there is no file in my bucket when I check DigitalOcean

Any help is appreciated!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

×
5 answers

Hey friend,

That is an interesting one. As this isn’t something I code in specifically, I’m thinking a bit high level here. Maybe it can stir up the right idea though. My thought is, can you have the code output a debug message that includes the raw response from our API? That may give some more insight into what is happening.

Kind Regards,
Jarland

  • Hello and thank you for your response!

    I wasn’t exactly sure how to generate the message that you are looking for.

    I added console.log(res) right above console.log(“File uploaded successfully.”);

    I’m not sure if that provides any useful information or not, but this is what I got:

    ServerResponse {
      domain: null,
      _events: { finish: [Function: bound resOnFinish] },
      _eventsCount: 1,
      _maxListeners: undefined,
      output: [],
      outputEncodings: [],
      outputCallbacks: [],
      outputSize: 0,
      writable: true,
      _last: false,
      upgrading: false,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: true,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: false,
      _headerSent: false,
      socket: 
       Socket {
         connecting: false,
         _hadError: false,
         _handle: 
          TCP {
            reading: true,
            owner: [Circular],
            onread: [Function: onread],
            onconnection: null,
            writeQueueSize: 0,
            _consumed: true },
         _parent: null,
         _host: null,
         _readableState: 
          ReadableState {
            objectMode: false,
            highWaterMark: 16384,
            buffer: [Object],
            length: 0,
            pipes: null,
            pipesCount: 0,
            flowing: true,
            ended: false,
            endEmitted: false,
            reading: true,
            sync: false,
            needReadable: true,
            emittedReadable: false,
            readableListening: false,
            resumeScheduled: false,
            destroyed: false,
            defaultEncoding: 'utf8',
            awaitDrain: 0,
            readingMore: false,
            decoder: null,
            encoding: null },
         readable: true,
         domain: null,
         _events: 
          { end: [Array],
            finish: [Function: onSocketFinish],
            _socketEnd: [Function: onSocketEnd],
            drain: [Array],
            timeout: [Function: socketOnTimeout],
            data: [Function: bound socketOnData],
            error: [Function: socketOnError],
            close: [Array],
            resume: [Function: onSocketResume],
            pause: [Function: onSocketPause] },
         _eventsCount: 10,
         _maxListeners: undefined,
         _writableState: 
          WritableState {
            objectMode: false,
            highWaterMark: 16384,
            finalCalled: false,
            needDrain: false,
            ending: false,
            ended: false,
            finished: false,
            destroyed: false,
            decodeStrings: false,
            defaultEncoding: 'utf8',
            length: 0,
            writing: false,
            corked: 0,
            sync: false,
            bufferProcessing: false,
            onwrite: [Function: bound onwrite],
            writecb: null,
            writelen: 0,
            bufferedRequest: null,
            lastBufferedRequest: null,
            pendingcb: 0,
            prefinished: false,
            errorEmitted: false,
            bufferedRequestCount: 0,
            corkedRequestsFree: [Object] },
         writable: true,
         allowHalfOpen: true,
         _bytesDispatched: 432,
         _sockname: null,
         _pendingData: null,
         _pendingEncoding: '',
         server: 
          Server {
            domain: null,
            _events: [Object],
            _eventsCount: 2,
            _maxListeners: undefined,
            _connections: 1,
            _handle: [Object],
            _usingSlaves: false,
            _slaves: [],
            _unref: false,
            allowHalfOpen: true,
            pauseOnConnect: false,
            httpAllowHalfOpen: false,
            timeout: 120000,
            keepAliveTimeout: 5000,
            _pendingResponseData: 0,
            maxHeadersCount: null,
            _connectionKey: '6::::8000',
            [Symbol(asyncId)]: 14 },
         _server: 
          Server {
            domain: null,
            _events: [Object],
            _eventsCount: 2,
            _maxListeners: undefined,
            _connections: 1,
            _handle: [Object],
            _usingSlaves: false,
            _slaves: [],
            _unref: false,
            allowHalfOpen: true,
            pauseOnConnect: false,
            httpAllowHalfOpen: false,
            timeout: 120000,
            keepAliveTimeout: 5000,
            _pendingResponseData: 0,
            maxHeadersCount: null,
            _connectionKey: '6::::8000',
            [Symbol(asyncId)]: 14 },
         _idleTimeout: 120000,
         _idleNext: 
          TimersList {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            _timer: [Object],
            _unrefed: true,
            msecs: 120000,
            nextTick: false },
         _idlePrev: 
          TimersList {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            _timer: [Object],
            _unrefed: true,
            msecs: 120000,
            nextTick: false },
         _idleStart: 22863,
         _destroyed: false,
         parser: 
          HTTPParser {
            '0': [Function: parserOnHeaders],
            '1': [Function: parserOnHeadersComplete],
            '2': [Function: parserOnBody],
            '3': [Function: parserOnMessageComplete],
            '4': [Function: bound onParserExecute],
            _headers: [],
            _url: '',
            _consumed: true,
            socket: [Circular],
            incoming: [Object],
            outgoing: null,
            maxHeaderPairs: 2000,
            onIncoming: [Function: bound parserOnIncoming] },
         on: [Function: socketOnWrap],
         _paused: false,
         read: [Function],
         _consuming: true,
         _httpMessage: [Circular],
         [Symbol(asyncId)]: 467,
         [Symbol(bytesRead)]: 0,
         [Symbol(asyncId)]: 469,
         [Symbol(triggerAsyncId)]: 467 },
      connection: 
       Socket {
         connecting: false,
         _hadError: false,
         _handle: 
          TCP {
            reading: true,
            owner: [Circular],
            onread: [Function: onread],
            onconnection: null,
            writeQueueSize: 0,
            _consumed: true },
         _parent: null,
         _host: null,
         _readableState: 
          ReadableState {
            objectMode: false,
            highWaterMark: 16384,
            buffer: [Object],
            length: 0,
            pipes: null,
            pipesCount: 0,
            flowing: true,
            ended: false,
            endEmitted: false,
            reading: true,
            sync: false,
            needReadable: true,
            emittedReadable: false,
            readableListening: false,
            resumeScheduled: false,
            destroyed: false,
            defaultEncoding: 'utf8',
            awaitDrain: 0,
            readingMore: false,
            decoder: null,
            encoding: null },
         readable: true,
         domain: null,
         _events: 
          { end: [Array],
            finish: [Function: onSocketFinish],
            _socketEnd: [Function: onSocketEnd],
            drain: [Array],
            timeout: [Function: socketOnTimeout],
            data: [Function: bound socketOnData],
            error: [Function: socketOnError],
            close: [Array],
            resume: [Function: onSocketResume],
            pause: [Function: onSocketPause] },
         _eventsCount: 10,
         _maxListeners: undefined,
         _writableState: 
          WritableState {
            objectMode: false,
            highWaterMark: 16384,
            finalCalled: false,
            needDrain: false,
            ending: false,
            ended: false,
            finished: false,
            destroyed: false,
            decodeStrings: false,
            defaultEncoding: 'utf8',
            length: 0,
            writing: false,
            corked: 0,
            sync: false,
            bufferProcessing: false,
            onwrite: [Function: bound onwrite],
            writecb: null,
            writelen: 0,
            bufferedRequest: null,
            lastBufferedRequest: null,
            pendingcb: 0,
            prefinished: false,
            errorEmitted: false,
            bufferedRequestCount: 0,
            corkedRequestsFree: [Object] },
         writable: true,
         allowHalfOpen: true,
         _bytesDispatched: 432,
         _sockname: null,
         _pendingData: null,
         _pendingEncoding: '',
         server: 
          Server {
            domain: null,
            _events: [Object],
            _eventsCount: 2,
            _maxListeners: undefined,
            _connections: 1,
            _handle: [Object],
            _usingSlaves: false,
            _slaves: [],
            _unref: false,
            allowHalfOpen: true,
            pauseOnConnect: false,
            httpAllowHalfOpen: false,
            timeout: 120000,
            keepAliveTimeout: 5000,
            _pendingResponseData: 0,
            maxHeadersCount: null,
            _connectionKey: '6::::8000',
            [Symbol(asyncId)]: 14 },
         _server: 
          Server {
            domain: null,
            _events: [Object],
            _eventsCount: 2,
            _maxListeners: undefined,
            _connections: 1,
            _handle: [Object],
            _usingSlaves: false,
            _slaves: [],
            _unref: false,
            allowHalfOpen: true,
            pauseOnConnect: false,
            httpAllowHalfOpen: false,
            timeout: 120000,
            keepAliveTimeout: 5000,
            _pendingResponseData: 0,
            maxHeadersCount: null,
            _connectionKey: '6::::8000',
            [Symbol(asyncId)]: 14 },
         _idleTimeout: 120000,
         _idleNext: 
          TimersList {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            _timer: [Object],
            _unrefed: true,
            msecs: 120000,
            nextTick: false },
         _idlePrev: 
          TimersList {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            _timer: [Object],
            _unrefed: true,
            msecs: 120000,
            nextTick: false },
         _idleStart: 22863,
         _destroyed: false,
         parser: 
          HTTPParser {
            '0': [Function: parserOnHeaders],
            '1': [Function: parserOnHeadersComplete],
            '2': [Function: parserOnBody],
            '3': [Function: parserOnMessageComplete],
            '4': [Function: bound onParserExecute],
            _headers: [],
            _url: '',
            _consumed: true,
            socket: [Circular],
            incoming: [Object],
            outgoing: null,
            maxHeaderPairs: 2000,
            onIncoming: [Function: bound parserOnIncoming] },
         on: [Function: socketOnWrap],
         _paused: false,
         read: [Function],
         _consuming: true,
         _httpMessage: [Circular],
         [Symbol(asyncId)]: 467,
         [Symbol(bytesRead)]: 0,
         [Symbol(asyncId)]: 469,
         [Symbol(triggerAsyncId)]: 467 },
      _header: null,
      _onPendingData: [Function: bound updateOutgoingData],
      _sent100: false,
      _expect_continue: false,
      req: 
       IncomingMessage {
         _readableState: 
          ReadableState {
            objectMode: false,
            highWaterMark: 16384,
            buffer: [Object],
            length: 0,
            pipes: null,
            pipesCount: 0,
            flowing: true,
            ended: true,
            endEmitted: true,
            reading: false,
            sync: false,
            needReadable: false,
            emittedReadable: false,
            readableListening: false,
            resumeScheduled: false,
            destroyed: false,
            defaultEncoding: 'utf8',
            awaitDrain: 0,
            readingMore: false,
            decoder: null,
            encoding: null },
         readable: false,
         domain: null,
         _events: {},
         _eventsCount: 0,
         _maxListeners: undefined,
         socket: 
          Socket {
            connecting: false,
            _hadError: false,
            _handle: [Object],
            _parent: null,
            _host: null,
            _readableState: [Object],
            readable: true,
            domain: null,
            _events: [Object],
            _eventsCount: 10,
            _maxListeners: undefined,
            _writableState: [Object],
            writable: true,
            allowHalfOpen: true,
            _bytesDispatched: 432,
            _sockname: null,
            _pendingData: null,
            _pendingEncoding: '',
            server: [Object],
            _server: [Object],
            _idleTimeout: 120000,
            _idleNext: [Object],
            _idlePrev: [Object],
            _idleStart: 22863,
            _destroyed: false,
            parser: [Object],
            on: [Function: socketOnWrap],
            _paused: false,
            read: [Function],
            _consuming: true,
            _httpMessage: [Circular],
            [Symbol(asyncId)]: 467,
            [Symbol(bytesRead)]: 0,
            [Symbol(asyncId)]: 469,
            [Symbol(triggerAsyncId)]: 467 },
         connection: 
          Socket {
            connecting: false,
            _hadError: false,
            _handle: [Object],
            _parent: null,
            _host: null,
            _readableState: [Object],
            readable: true,
            domain: null,
            _events: [Object],
            _eventsCount: 10,
            _maxListeners: undefined,
            _writableState: [Object],
            writable: true,
            allowHalfOpen: true,
            _bytesDispatched: 432,
            _sockname: null,
            _pendingData: null,
            _pendingEncoding: '',
            server: [Object],
            _server: [Object],
            _idleTimeout: 120000,
            _idleNext: [Object],
            _idlePrev: [Object],
            _idleStart: 22863,
            _destroyed: false,
            parser: [Object],
            on: [Function: socketOnWrap],
            _paused: false,
            read: [Function],
            _consuming: true,
            _httpMessage: [Circular],
            [Symbol(asyncId)]: 467,
            [Symbol(bytesRead)]: 0,
            [Symbol(asyncId)]: 469,
            [Symbol(triggerAsyncId)]: 467 },
         httpVersionMajor: 1,
         httpVersionMinor: 1,
         httpVersion: '1.1',
         complete: true,
         headers: 
          { host: 'localhost:8000',
            'user-agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0',
            accept: 'application/json, text/plain, */*',
            'accept-language': 'en-US,en;q=0.5',
            'accept-encoding': 'gzip, deflate',
            referer: 'http://localhost:8080/',
            'content-type': 'application/json;charset=utf-8',
            'content-length': '2',
            origin: 'http://localhost:8080',
            connection: 'keep-alive',
            dnt: '1' },
         rawHeaders: 
          [ 'Host',
            'localhost:8000',
            'User-Agent',
            'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0',
            'Accept',
            'application/json, text/plain, */*',
            'Accept-Language',
            'en-US,en;q=0.5',
            'Accept-Encoding',
            'gzip, deflate',
            'Referer',
            'http://localhost:8080/',
            'Content-Type',
            'application/json;charset=utf-8',
            'Content-Length',
            '2',
            'Origin',
            'http://localhost:8080',
            'Connection',
            'keep-alive',
            'DNT',
            '1' ],
         trailers: {},
         rawTrailers: [],
         upgrade: false,
         url: '/upload',
         method: 'POST',
         statusCode: null,
         statusMessage: null,
         client: 
          Socket {
            connecting: false,
            _hadError: false,
            _handle: [Object],
            _parent: null,
            _host: null,
            _readableState: [Object],
            readable: true,
            domain: null,
            _events: [Object],
            _eventsCount: 10,
            _maxListeners: undefined,
            _writableState: [Object],
            writable: true,
            allowHalfOpen: true,
            _bytesDispatched: 432,
            _sockname: null,
            _pendingData: null,
            _pendingEncoding: '',
            server: [Object],
            _server: [Object],
            _idleTimeout: 120000,
            _idleNext: [Object],
            _idlePrev: [Object],
            _idleStart: 22863,
            _destroyed: false,
            parser: [Object],
            on: [Function: socketOnWrap],
            _paused: false,
            read: [Function],
            _consuming: true,
            _httpMessage: [Circular],
            [Symbol(asyncId)]: 467,
            [Symbol(bytesRead)]: 0,
            [Symbol(asyncId)]: 469,
            [Symbol(triggerAsyncId)]: 467 },
         _consuming: true,
         _dumped: false,
         next: [Function: next],
         baseUrl: '',
         originalUrl: '/upload',
         _parsedUrl: 
          Url {
            protocol: null,
            slashes: null,
            auth: null,
            host: null,
            port: null,
            hostname: null,
            hash: null,
            search: null,
            query: null,
            pathname: '/upload',
            path: '/upload',
            href: '/upload',
            _raw: '/upload' },
         params: {},
         query: {},
         res: [Circular],
         _parsedOriginalUrl: 
          Url {
            protocol: null,
            slashes: null,
            auth: null,
            host: null,
            port: null,
            hostname: null,
            hash: null,
            search: null,
            query: null,
            pathname: '/upload',
            path: '/upload',
            href: '/upload',
            _raw: '/upload' },
         sessionStore: 
          MemoryStore {
            domain: null,
            _events: [Object],
            _eventsCount: 2,
            _maxListeners: undefined,
            sessions: [Object],
            generate: [Function] },
         sessionID: 'ryhvN2OOWE8CRIKNNxSRojA1RbKvrNNI',
         session: Session { cookie: [Object] },
         _validationCustomMethods: { sanitizers: {}, validators: {} },
         _validationErrors: [],
         _asyncValidationErrors: [],
         validationErrors: [Function],
         asyncValidationErrors: [Function],
         getValidationResult: [Function],
         sanitizeBody: [Function],
         sanitizeParams: [Function],
         sanitizeQuery: [Function],
         sanitizeCookies: [Function],
         sanitizeHeaders: [Function],
         sanitize: [Function],
         checkBody: [Function],
         checkParams: [Function],
         checkQuery: [Function],
         checkCookies: [Function],
         checkHeaders: [Function],
         check: [Function],
         filter: [Function],
         assert: [Function],
         validate: [Function],
         _passport: { instance: [Object] },
         body: {},
         _body: true,
         length: undefined,
         read: [Function],
         route: Route { path: '/upload', stack: [Array], methods: [Object] } },
      locals: {},
      writeHead: [Function: writeHead],
      end: [Function: end],
      [Symbol(outHeadersKey)]: 
       { 'x-powered-by': [ 'X-Powered-By', 'Express' ],
         'access-control-allow-origin': [ 'Access-Control-Allow-Origin', '*' ] } }
    
    code
    

    I should also note that in my original post and how I have been working with the code, I have the headers: {“Content-Type”: “multipart/form-data”} commented out in the axios post. From what I was reading, I may actually need to include that and uncomment it? If I do uncomment that code, I receive this error message on the server when I hit submit on the upload

    Error: Multipart: Boundary not found
        at new Multipart (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/busboy/lib/types/multipart.js:58:11)
        at Multipart (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/busboy/lib/types/multipart.js:26:12)
        at Busboy.parseHeaders (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/busboy/lib/main.js:71:22)
        at new Busboy (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/busboy/lib/main.js:22:10)
        at multerMiddleware (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/multer/lib/make-middleware.js:33:16)
        at index (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/controllers/Uploads.js:29:5)
        at Layer.handle [as handle_request] (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/layer.js:95:5)
        at next (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/route.js:137:13)
        at Route.dispatch (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/route.js:112:3)
        at Layer.handle [as handle_request] (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/layer.js:95:5)
        at /media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/index.js:281:22
        at Function.process_params (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/index.js:335:12)
        at next (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/express/lib/router/index.js:275:10)
        at cors (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/cors/lib/index.js:188:7)
        at /media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/cors/lib/index.js:224:17
        at originCallback (/media/rob/cdcda95a-f6c7-458a-abe5-b3f3a3629e8a/photo-wall/server/node_modules/cors/lib/index.js:214:15)
    
    code
    

I dont see where you put your access and secret key credentials when you’re instantiating S3.

You should have gotten a 401 Unauthorized error with that code.

  • Hello and thank you for the reply!

    My credentials are locally on my machine (I followed the steps in the tutorial referenced in my first post to do that). I don’t think that is the problem because I successfully uploaded a text file.

Hi! Any updates here? I need upload images from a react native app to Spaces…!

Sorry. How can i have Location Url of this file

Hello, I’m facing the same issue right now but with Cloudinary storage.
what I noticed while facing this problem is that:
- Upload with postman works just fine. (which you can try to see if works with you too)
- The post request I send from axios to the server fails after exactly 4 min. (which means the server is not responding in that 4 min)
- When I consoled log the progress of the file upload in axios. I got that the file is completely uploaded.

This is my position now, I’m trying to figure a way out of this problem

Submit an Answer