23

I have used the Winston module to create a daily log file for my offline app. I now need to be able to send or upload that file to a remote server via POST (that part already exists)

I know I need to write the file in chunks so it doesn't hog the memory so I'm using fs.createReadStream however I seem to only get a 503 response, even if sending just sample text.

EDIT

I worked out that the receiver was expecting the data to be named 'data'. I have removed the createReadSteam as I could only get it to work with 'application/x-www-form-urlencoded' and a synchronous fs.readFileSync. If I change this to 'multipart/form-data' on the php server would I be able to use createReadStream again, or is that only if I change to physically uploading the json file.

I've only been learning node for the past couple of weeks so any pointers would be gratefully received.

var http = require('http'),
    fs = require('fs');

var post_options = {
    host: 'logger.mysite.co.uk',
    path: '/',
    port: 80,
    timeout: 120000,
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
}

var sender = http.request(post_options, function(res) {
    if (res.statusCode < 399) {
        var text = ""
        res.on('data', function(chunk) {
            text += chunk
        })
        res.on('end', function(data) {
            console.log(text)
        })
    } else {
        console.log("ERROR", res.statusCode)
    }
})

var POST_DATA = 'data={['
POST_DATA += fs.readFileSync('./path/file.log').toString().replace(/\,+$/,'')
POST_DATA += ']}'
console.log(POST_DATA)
sender.write(POST_DATA)
sender.end()
sidonaldson
  • 24,431
  • 10
  • 56
  • 61
  • 1
    Have you tried uploading the file using something like `curl` to make sure the remote server actually accepts the data? It might have issues with the `application/json` content type. Also, is the logfile actually in JSON format? – robertklep Nov 06 '13 at 17:44
  • You may have a point here. Is there any difference between uploading a json file or opening a json file and sending it as POST data chunks (not actually sending the file) – sidonaldson Nov 07 '13 at 00:55
  • If you send it with `application/json` as `Content-Type`, the file may not get treated as a 'regular' upload. If you want a regular upload, you should consider using either `request` or at least [`form-data`](https://github.com/felixge/node-form-data) because file uploads are not trivial to implement. – robertklep Nov 07 '13 at 04:56
  • Is that actually what the server expects? It looks pretty weird. – robertklep Nov 07 '13 at 11:42
  • 503 is server unavailable - is the server down? http://www.checkupdown.com/status/E503.html – bryanmac Nov 07 '13 at 11:43
  • @bryanmac I think the server in this case sends back a 503 when it receives data in a form it cannot handle. – robertklep Nov 07 '13 at 11:45
  • @bryanmac it's an appfog server btw. Turns out this error goes away if I manually work out the length of the post data in bytes and set the correct content length. I'm slowly getting there! – sidonaldson Nov 07 '13 at 15:00
  • omg... the lack of semicolons here give me a cancer. – mr5 Feb 16 '15 at 05:14

4 Answers4

11

After gazillion of trial-failure this worked for me. Using FormData with node-fetch. Oh, and request deprecated two days ago, btw.

const FormData = require('form-data');
const fetch = require('node-fetch');

function uploadImage(imageBuffer) {
  const form = new FormData();
  form.append('file', imageBuffer, {
    contentType: 'image/jpeg',
    filename: 'dummy.jpg',
  });
  return fetch(`myserver.cz/upload`, { method: 'POST', body: form })
};

In place of imageBuffer there can be numerous things. I had a buffer containing the image, but you can also pass the result of fs.createReadStream('/foo/bar.jpg') to upload a file from drive.

kub1x
  • 3,272
  • 37
  • 38
9

copied from https://github.com/mikeal/request#forms

var r = request.post('http://service.com/upload', function optionalCallback (err, httpResponse, body) {
  if (err) {
    return console.error('upload failed:', err);
  }
  console.log('Upload successful!  Server responded with:', body);
})
var form = r.form()
form.append('my_field1', 'my_value23_321')
form.append('my_field2', '123123sdas')
form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png')))
waqas
  • 4,357
  • 3
  • 34
  • 42
  • 1
    Request just deprecated https://github.com/request/request/issues/3142 see my answer using `node-fetch` and `FormData`: https://stackoverflow.com/a/60208227/336753 – kub1x Feb 13 '20 at 12:49
0

I would recommend using axios for uploading it to a remote server.

const { default: axios } = require("axios")
const fs = require('fs');

const path = '/path/to/your/file.{extension}'
const file = fs.readFileSync(path) /** Read file */
const stats = fs.statSync(path) /** Get file size in bytes (for content-length) */
const fileSizeInBytes = stats.size;

/** Add appropriate headers */
const headers = {
  'Authorization': 'Bearer Your Token', /** Optional */
  'Content-Length': fileSizeInBytes, /** Recommended to add it */
  'Content-Type': 'application/octet-stream',
}
let url = "https://www.example.com/remote-server-upload-url"

axios.post(url, file, {
    headers: headers,
    maxContentLength: Infinity, /** To avoid max content length error */
    maxBodyLength: Infinity /** To avoid max body length error */
}).then((response) => {
    return response.data
}).catch((error) => {
    return error
})
Nouman Mukhtar
  • 329
  • 4
  • 6
-1

Have a look at the request module.

It will provide you the ability to stream a file to POST requests.

swhitewvu24
  • 284
  • 1
  • 5
  • I see that. Request allows you to stream a file directly to another request. Have a look at the documentation. – swhitewvu24 Nov 06 '13 at 19:01
  • From the docs: fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json')) – swhitewvu24 Nov 06 '13 at 19:02
  • I agree that `request` is very nice, but the remote server is throwing a fit because of the upload so I don't think replacing `http` with `request` will solve the problem :) The original code, albeit a bit verbose, should work. – robertklep Nov 06 '13 at 19:05
  • Plus I'm trying to learn node where possible. I've looked at request before and might have to as this is quite complex. – sidonaldson Nov 07 '13 at 00:54
  • 2
    @sidonaldson using great modules made by others is also part of learning Node ;) – robertklep Nov 07 '13 at 11:45
  • 1
    @robertklep when I first started looking at node I found request to be too confusing, almost like it did too much too soon, now I know if I went back and started again it would make a lot more sense. – sidonaldson Nov 07 '13 at 15:01