Vladislav
Vladislav

Reputation: 533

Piping a stream to request post doesn't work

I've read on request's documentation page that one can stream a file to a PUT or POST request, like this:

fs.createReadStream('file.json').pipe(request.put('http://example.com/obj.json'));
request.get('http://google.com/img.png').pipe(request.put('http://example.com/img.png'));    

But it seems to be not working. I've tried to set up a local server for uploading files using different libraries.

express-busboy:

var express = require('express');
var app = express();
var fs = require('fs');
var bb = require('express-busboy');
var app = express();
bb.extend(app, {
    upload: true,
    path: './img/',
    allowedPath: /./
});

app.post('/upload', function(req, res) {
    console.log(req.files);
});

var server = app.listen(process.env.PORT, function() {
    console.log('Listening on port %d', server.address().port);
});

and formidable:

var express = require('express');
var app = express();
var path = require('path');     
var fs = require('fs');     
var formidable = require('formidable');

app.post('/upload', function(req, res){

    // create an incoming form object
    var form = new formidable.IncomingForm();

    // specify that we want to allow the user to upload multiple files in a single request
    form.multiples = true;

    // store all uploads in the /uploads directory
    form.uploadDir = path.join(__dirname, '/img');

    // every time a file has been uploaded successfully,
    // rename it to it's orignal name
    form.on('file', function(field, file) {
        fs.rename(file.path, path.join(form.uploadDir, file.name));
    });

    // log any errors that occur
    form.on('error', function(err) {
        console.log('An error has occured: \n' + err);
    });

   // once all the files have been uploaded, send a response to the client
   form.on('end', function() {
      res.end('success');
   });

  // parse the incoming request containing the form data
  form.parse(req);

});

var server = app.listen(process.env.PORT, function() {
    console.log('Listening on port %d', server.address().port);
});

Both work fine when I'm making request like this:

var request = require('request');
var fs = require('fs');
var formData = {
      filename: {
      value:  fs.createReadStream('ice.jpg'),
      options: {
        filename: 'ice.jpg',
        contentType: ' image/jpeg'
      }}
  };

request.post({url: 'https://myserver.com/upload', formData: formData});

Or from the command line:

curl -i -X POST -H "Content-Type: multipart/form-data" -F "[email protected]" https://myserver.com/upload

But none of them work when I'm trying to do this:

fs.createReadStream('ice.jpg').pipe(request.post('https://myserver.com/upload'));

Am I doing something wrong? Is there a way to make the last line to work?

Upvotes: 3

Views: 6988

Answers (1)

Vladislav
Vladislav

Reputation: 533

OK. I'm answering the question in case someone will have the similar problem.

Curl and request.post with formData option both send post requests with a "Content-Type: multipart/form-data" header. Libraries like express-busboy, formidable, and multer are used to parse that data.

This line:

fs.createReadStream('ice.jpg').pipe(request.post('https://myserver.com/upload'));

send a request with "Content-Type: image/jpeg" and "Transfer-Encoding: chunked" headers. No need to parse multipart form data here.

The following code on the server will work in this type of scenario:

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

var server = http.createServer(function(req, res){
    console.log(req.headers);
    var body = [];
    req
      .on('data', chunk => {
          body.push(chunk);
          console.log('Chunk ', chunk);
          })
      .on('end', () => {
          body = Buffer.concat(body);
          fs.writeFileSync('newfile.jpg', body, null);
      });
    res.write("OK\n");
    res.end();
});

Upvotes: 4

Related Questions