5

I want to return a pdf from a AWS Lambda function, and I use API Gateway for calling it from a any browser.

I have a aws lambda function in c# that returns an API Gateway Response which body is a pdf in base64 encoded string.

So far the endpoint returns a file with .pdf extension but not in binary. Instead, is a text file with the base64 string.

The headers i'm returning from the c# code are:

  var headersDic = new Dictionary<string, string>();
      headersDic.Add("Content-type", "application/pdf");
      headersDic.Add("Content-disposition", "attachment; filename=file.pdf");

I converted manually the base64 string to binary file and opened it as a pdf, and it works, I mean, the base64 string is correct so I assume the problem is being the API Gateway.

In the integration response console of the API Gateway, I got this:

enter image description here

But i'm not able to make it work.

I also have binary media types enabled.

enter image description here

1
  • Hi do u have any solution for this? Commented Mar 19, 2021 at 14:36

4 Answers 4

5

Actually, you do not have to disable Lambda Proxy Integration, nor do you have to specify "*/*" as a Binary Media Type, nor do you have to have your Lambda code convert the output to Base64, nor do you have to modify LambdaEntryPoint in order to get this to work.

Although some sources indicate that the "*/*" entry is necessary, the answer lies in the comment accompanying the Binary Media Types setting:

"API Gateway will look at the Content-Type and Accept HTTP headers to decide how to handle the body."

In other words, for some odd reason, rather than just paying attention to the returned Content-Type in applying the Binary Media Types list, the gateway also takes into account the requesting client's Accept header. Most clients default to Accept:*/*, thus the origin of the workaround, and the most common explanation as to why this list doesn't seem to work. Not only does the client's Accept header seem to be given more credence than the returned Content-Type value here, there is no semantic assessment of "*/*". It is not evaluated as a wildcard, which should match any content type. Thus, an exact match of said value, literally "*/*", winds up being needed in the Binary Media Types list.

A simple solution (one which works for me) is to:

  • Have the client, instead of specifying "*/*" in its Accept header, specify the actual expected MIME type. (Do not specify multiple Accept types, as only the first listed type is evaluated.)
  • Include the same MIME type in the Binary Media Types list. Do not specify "*/*".
  • Have the Lambda function return a non-Base64-encoded binary file, specifying its actual MIME type in the Content-Type header. For instance, in C#, by returning a FileContentResult from the ControllerBase.File() method, specifying the appropriate MIME content type, as in:
return File(pdfContents, "application/pdf"); //pdfContents contains raw binary data

API Gateway will match the data type to its Binary Media Types list and regard the returned data as binary. So far, I have not needed to insert RegisterResponseContentEncodingForContentType() in LambdaEntryPoint.Init().

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

Comments

0

I don't know exactly what I did, but I deleted the 'ALL' method, and created the 'GET' method with this config and now it works.

enter image description here

3 Comments

how did you include Content-disposition header in response? my backend is returning Content-disposition but api gateway is not including it in the response
What do you mean by content-disposition? it has passed long enough to not remember too much of this.
Have you had Lambda Proxy Integration enabled before? I have the same problem with correct base64 encoded data returned by the gateway but not in binary.
0

You also need to declare the content type like the following in your LambdaEntryPoint.cs

See this documentation: https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.AspNetCoreServer/README.md

You have to tell Lambda you're going to return something besides strings.

public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{

    protected override void Init(IWebHostBuilder builder)
    {
        builder
            .UseStartup<Startup>();

        ****IMPORTANT PART HERE****
        RegisterResponseContentEncodingForContentType("application/pdf",
            ResponseContentEncoding.Base64);
    }
}

Comments

0

Response Headers

'Content-Type': 'application/pdf'
'Content-disposition', 'attachment; filename=fileName.pdf'

Response to Client

{
 statusCode: 200
 headers: responseHeader,
 body: pdfContent.toString(base64),
 isBase64Encoded: true,
}

API Gateway Binary Media Types

enter image description here

Hope it will help

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.