3

I'm building an Angular / Node.js application connected to a DMS (Alfresco). The server side Node.js / Express layer acts as a proxy to hide the complexity of Alfresco from the client:

Angular client <--> Node backend <--> Alfresco

This question is only about the Node.js backend.

When uploading a file I would like to forward the incoming file directly to Alfresco without temporarily storing it on the disk. With temporary disk storage this works as expected:

const fileUpload = require('express-fileupload');
const FormData = require('form-data');

// app is the express object
app.use(fileUpload({ createParentPath: true }));

app.post('/file', async (req, res) => {

    // filedata is the FormData field of the client containing the actual file
    let file = req.files.filedata;
    let tmpPath = __dirname + '/tmp/' + file.name;

    // save the file temporarily on the server
    file.mv(tmpPath, async function(err) {

        // create a new FormData Object for the upload to the DMS
        const formData = new FormData();
        formData.append('name', name);
        // creates an fs.ReadStream object which is inherited from stream.Readable
        formData.append('filedata', fs.createReadStream(tmpPath));
    
        // upload the file to the DMS
        let response = await axios.post('/files/...', formData, { headers: formData.getHeaders() });
        
        // remove the temporary file
        fs.rm(tmpPath, () => {

            // return the answer of the DMS to the client
            res.send(response.data);
        });
    });
});

Now I would like to avoid the disk access and forward the file directly to the DMS. Taking into consideration Converting a Buffer into a ReadableStream in Node.js I tried the following three alternatives.

const { Readable } = require('stream');

app.post('/file', async (req, res) => {
    let file = req.files.fileData;

    // create a new FormData Object for the upload to the DMS
    const formData = new FormData();
    formData.append('name', name);

    /* alternatives starting here */
    // Source: https://stackoverflow.com/questions/13230487/
    
    // #1
    const readable = new Readable();
    readable._read = () => {};
    readable.push(file.data);
    readable.push(null);
    
    // #2
    const readable = new Readable();
    readable._read = () => {};
    const buffer = new Buffer(file.data, 'utf-8');
    readable.push(buffer);  
    readable.push(null);
    
    // #3
    const readable = Readable.from(file.data);

    /* alternatives ending here */

    // put the Readable into the FormData object
    formData.append('filedata', readable);

    // upload the file to the DMS
    let response = await axios.post('/files/...', formData, { headers: formData.getHeaders() });

    // return the answer of the DMS to the client
    res.send(response.data);
});

Whatever alternative I try, Alfresco always complains, required fields would be missing. Nonetheless, all required fields are provided, since the example with storing the file temporarily works fine. I think, Alfresco cannot handle the stream I provide and that I have a problem to completely understand how streams work in this situation. What should I do differently?

Please note, that all error handling as well as Alfresco request configuration / API URL is omitted for the sake of readability.

trsft
  • 109
  • 1
  • 6

1 Answers1

2

try providing file related information such as filename, knownLength etc.

let file = req.files.fileData;

const formData = new FormData();
// buffer with file related info
formData.append(name, file.data, {
    filename: file.name,
    contentType: file.mimetype,
    knownLength: file.size
});

// upload the file to the DMS
let response = await axios.post('/files/...', formData, {headers: formData.getHeaders() });

// return the answer of the DMS to the client
res.send(response.data);
traynor
  • 5,490
  • 3
  • 13
  • 23
  • 1
    This type of data is omitted as stated in my question since this is not the problem. In the actual implementation all necessary information of this kind is provided. The problem is about the handling of streams and buffers. – trsft Mar 01 '22 at 15:19
  • 1
    FWIW this solution helped my problem here: https://stackoverflow.com/questions/75036668/unable-to-send-a-file-via-an-http-post-request-because-the-file-extension-is-inc. The file is coming from S3 which is slightly different though and being sent to another client via a HTTP POST request. – hikarunoryoma Jan 09 '23 at 20:53