问题
We are streaming content from S3 in node using createReadStream()
in aws-sdk. We would like to add etag support. If we add the 'If-None-Match' header from the client, s3 throws NotModified as an error that I can't seem to handle.
retrieveFile = function(req, res) {
var s3 = new AWS.S3();
var params = {
Bucket: bucket,
key: key
};
if (req.get('If-None-Match')) {
params.IfNoneMatch = req.get('If-None-Match');
}
return s3.getObject(params).on('httpHeaders', function(statusCode, headers) {
if (headers.etag) {
res.set('etag', headers.etag);
}
if (headers['content-length']) {
return res.set('content-length', headers['content-length']);
}
}).createReadStream().pipe(res);
};
I've tried listening to events on the stream and using callbacks on the Request returned from getObject. I can get the error's message that way, but something else in aws-sdk appears to be killing my process.
/Projects/my-app/node_modules/aws-sdk/lib/request.js:31
throw err;
^
NotModified: null
at Request.extractError (/Projects/my-app/node_modules/aws-sdk/lib/services/s3.js:519:35)
at Request.callListeners (/Projects/my-app/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit (/Projects/my-app/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/Projects/my-app/node_modules/aws-sdk/lib/request.js:673:14)
at Request.transition (/Projects/my-app/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/Projects/my-app/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /Projects/my-app/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/Projects/my-app/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/Projects/my-app/node_modules/aws-sdk/lib/request.js:675:12)
at Request.callListeners (/Projects/my-app/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
at Request.emit (/Projects/my-app/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/Projects/my-app/node_modules/aws-sdk/lib/request.js:673:14)
at Request.transition (/Projects/my-app/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/Projects/my-app/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /Projects/my-app/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/Projects/my-app/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/Projects/my-app/node_modules/aws-sdk/lib/request.js:675:12)
at Request.callListeners (/Projects/my-app/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
at callNextListener (/Projects/my-app/node_modules/aws-sdk/lib/sequential_executor.js:95:12)
at IncomingMessage.onEnd (/Projects/my-app/node_modules/aws-sdk/lib/event_listeners.js:244:11)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickDomainCallback (internal/process/next_tick.js:122:9)
回答1:
It seems the error is thrown on the stream and if you're listening on the AWS.Request you'll receive an error, but the stream error is still not catched.
Consider this:
s3.getObject({
Bucket: 'foo',
Key: 'bar'
}).on('error', function (err) {
console.log('Error event!');
}).createReadStream();
This will show 'Error event!' but it will also throw an error and exit the process. That is because the stream created by createReadStream is also receiving an error.
Consider this:
s3.getObject({
Bucket: 'lalaland',
Key: 'blabaliets'
}).on('error', function (err) {
console.log('Error event!');
}).createReadStream().on('error', function (err) {
console.log('Error event on stream!');
});
It'll listen on the AWS.Request object for errors, but also on the stream object. This will first print 'Error event!', then 'Error event on stream!' and the process will not exit.
Note that this:
s3.getObject({
Bucket: 'lalaland',
Key: 'blabaliets'
}).createReadStream().on('error', function (err) {
console.log('Error event on stream!');
});
Will only print 'Error event on stream!' and not exit. This last option is probably what you want: only listen to errors on the stream and not on the request object.
To get back to your original intentions; at this point (in the on error on the stream) you want to check if it's indeed a NotModified error and do something like res.status(304).end()
.
来源:https://stackoverflow.com/questions/43238363/s3-streaming-with-etags-node