问题
I'm trying to GET a file file (source) and .pipe to a destination Box Upload endpoint using NodeJS Request. This approach worked fine on other cloud storage, like Dropbox, but Box requires multipart/form-data upload, so it fails with bad request. Due some requirements, I cannot use the Box NPM package and would prefer this pipe approach.
I'm probably missing some timing here as there is an error output:
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: write after end
at ClientRequest.OutgoingMessage.write (_http_outgoing.js:439:15)
at Request.write (/node_modules/request/request.js:1514:27)
at Request.ondata (stream.js:31:26)
at emitOne (events.js:96:13)
Tried use form-data, but no success, just changed the error and, aparently, the content-length was not right.
And here is my source code.
var source = {
url: SOURCE_DOWNLOAD_URL,
method: "GET",
headers: {
'Authorization': 'Bearer ' + SOURCE_TOKEN
},
encoding: null
};
var destination = {
url: 'https://upload.box.com/api/2.0/files/content',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + BOX_TOKEN
},
formData: JSON.stringify({
attributes: {
name: 'somename.txt',
parent: {
id: 1234
}
}
}),
encoding: null
};
request(source).pipe(request(destination)
.on('response', function (resDestination) {
// expecting 201, but returns 400
console.log(destination.method + ' ' + destination.url + ': ' + resDestination.statusCode + ' > ' + resDestination.statusMessage);
}));
回答1:
Try creating an intermediary stream that will collect all of the data before making the request to your destination
const Readable = require('stream').Readable
// Create a new Readable instance to write the original request data to
let sourceResponseStream = new Readable()
// no-op function to prevent _read() is not implemented error
sourceResponseStream._read = () => {}
let sourceReq = request(source)
// As we get chunks push them into our new Readable stream
sourceReq.on('data', chunk => {
sourceResponseStream.push(chunk)
})
// Listen for the end of the readable data from the request
sourceReq.on('end', () => {
// mark as no more data to read
sourceResponseStream.push(null)
// Make the request to the destination
let destReq = request(destination, (err, res, body) => {
if (err) {
// handle err
console.log(err)
} else {
console.log(`${destination.method} ${destination.url}: ${res.statusCode} > ${res.statusMessage}`)
}
})
// Pipe our response readable containing our source request data
sourceResponseStream.pipe(destReq)
})
If this doesn't work, you may want to add the sourceResponseStream
as a property on the formData
object. Also, you may want to remove the JSON.stringify()
around the formData.attributes
object. Not sure if that will affect how the request is processed.
来源:https://stackoverflow.com/questions/45037394/request-get-pipe-to-reqest-post-on-box