In another post I mentioned the neat features now available in AWS: Serverless templates.
As part of an experiment I thought it would be interesting to see how you could put a light security layer over S3 so that media requests stream from S3 if a user logs in.
The WebApi template already ships with an S3 proxy controller. Tweaking this slightly allowed me to stream or download the image:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
[HttpGet("{*key}")] public async Task Get(string key) { try { var getResponse = await S3Client.GetObjectAsync(new GetObjectRequest { BucketName = BucketName, Key = key }); Response.ContentType = getResponse.Headers.ContentType; getResponse.ResponseStream.CopyTo(Response.Body); } catch (AmazonS3Exception e) { Response.StatusCode = (int)e.StatusCode; var writer = new StreamWriter(Response.Body); writer.Write(e.Message); } } [HttpGet("dl/{*key}")] public async Task Download(string key) { try { var getResponse = await S3Client.GetObjectAsync(new GetObjectRequest { BucketName = BucketName, Key = key }); return File(getResponse.ResponseStream, "application/octet-stream"); } catch (AmazonS3Exception e) { Response.StatusCode = (int)e.StatusCode; var writer = new StreamWriter(Response.Body); writer.Write(e.Message); } return new EmptyResult(); } |
The issue I ran into was accessing images via the endpoint you then get in API Gateway – images were getting encoded so wouldn’t render in the browser.
The solution:
- In the settings for your api gateway, add the Binary Media Type: */*
- On the {proxy+} method ‘Method Response’ add a 200 response header and add a header Content-Type. Finally publish your api
The second step here may not be necessary but I found the */* didn’t kick in until I made the change.