3

I am in the process of trying to stream an mp4 video from my AWS S3 bucket onto a webpage using react.js for the client and node.js as the server. I am quite a bit new to both of these however. On the front-end, within one of my react components I have the following within a render, (some code in the return is omitted for relevance):

render() {
  const { classes } = this.props;
  return(
    <video id = "video" width = "1280" height = "720" controls>
    Your browser does not support the video tag.
      <source src={this.state.videoNow} type='video/mp4' />
    </video> 
  );
}

Within the same class I have a componentDidMount() function:

componentDidMount() {
   fetch("/api/annotate", {
     headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}
   })
     .then(res => {
       this.setState({
         videoNow: res
        });
      ,(error) => {
          console.log(error)
      })
}

Within my server.js file I have the following:

app.get('/api/annotate',
  (req, res) => {
    var s3 = new AWS.S3();
    const mimetype = 'video/mp4';
    const file = '<video source in bucket>';
    const cache = 0;
    console.log('const mimetype, file, and cache declared');
    s3.listObjectsV2({Bucket: <name of bucket>, MaxKeys: 1, Prefix: file}, function(err, data) {
      if (err) {
        return res.sendStatus(404);
      }
      console.log('made request to s3 to list objects');

      if ((req != null) && (req.headers.range != null)) {
        var range = req.headers.range;
        var bytes = range.replace(/bytes=/, '').split('-');
        var start = parseInt(bytes[0], 10);
        var total = data.Contents[0].Size;
        var end = bytes[1] ? parseInt(bytes[1], 10) : total - 1;
        var chunksize = (end - start) + 1;
        console.log('declared range, bytes, start, total, end, chunksize vars');

        res.writeHead(206, {
           'Content-Range'  : 'bytes ' + start + '-' + end + '/' + total,
           'Accept-Ranges'  : 'bytes',
           'Content-Length' : chunksize,
           'Last-Modified'  : data.Contents[0].LastModified,
           'Content-Type'   : mimetype
        });
        console.log('wrote header');
        s3.getObject({Bucket: <name of bucket>, Key: file, Range: range}).createReadStream().pipe(res);
        console.log('got object from s3 and created readstream');
      }
      else
      {
        res.writeHead(200,
        {
            'Cache-Control' : 'max-age=' + cache + ', private',
            'Content-Length': data.Contents[0].Size,
            'Last-Modified' : data.Contents[0].LastModified,
            'Content-Type'  : mimetype
        });
        s3.getObject({Bucket: <name of bucket>, Key: file}).createReadStream().pipe(res);
        console.log('fell into else statement, wrote header');
      }


    });
  });

When I run this code, I notice that the else statement in my server.js file is always run once, and then nothing else happens. The video doesn't load and the console states that the video could not be found. If I change the video source within my react component to src='/api/annotate' the video loads perfectly. The problem is that I am trying to add authentication, and this only works if I have a componentDidMount. I've been searching for days on how to solve this issue and couldn't find much. Once again, I am quite new to all of this. Any advice would be very much appreciated!!!

1
  • No idea how to help you with this one but in your promise functions when you fetch the data, you have a , instead of a . Commented Jul 26, 2018 at 2:42

1 Answer 1

2

Looks to me like you are trying to set the actual videodata in your source. That is not likely to work that way. Also, I am not sure why you are serving the file from S3 through your node.js server.

It seems like a much better solution if your node.js simply generated a pre-signed URL and returned that, which then could easily bet set as the source. They way all the data doesn't have to piped through your note app either.

Even better would be placing Cloudfront in front of your S3 bucket, and then using the same generating presigned URL's for that.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.