4

I'm trying to read a JS file (gzipped so that it can fit the lambda edge limits) locally using nodeJS and return it in the response but I get the error from title. Why is that? Is gzip body forbidden by aws edge?

 'use strict';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    var noCacheHeaders = {
        'cache-control': [{
            key: 'Cache-Control',
            value: 'no-cache'
        }],
        'pragma': [{
            key: 'Pragma',
            value: 'no-cache'
        }],
        'content-type': [{
            key: 'Content-Type',
            value: 'text/html'
        }]
    };
    if (request.uri.startsWith('/js/') === true) {
        console.log("js path");
        const fs = require('fs');
        fs.readFile('js.gz', function(err, data) {
            if (err) {
                console.log(err);
                // prevent caching on errors
                const response = {
                    status: '500',
                    statusDescription: 'OK',
                    headers: noCacheHeaders,
                    body: "",
                };
                callback(null, response);
            } else {
                const response = {
                    status: '200',
                    statusDescription: 'OK',
                    headers: noCacheHeaders,//cachedHeaders,
                    body: data.toString(),
                };
                callback(null, response);
            }
        });
        return;
    }

        callback(null, request);
        return;

};
2
  • 1
    Looks like you're sending the response as text/html content type, not JSON, no? Commented Jan 11, 2018 at 2:03
  • @xdumaine JSON refers to the serialization of the response or request object passed to callback() and received from Lambda when CloudFront invokes this function. It's always a JSON API behind the scenes, and CloudFront doesn't like something about the format of that document. Commented Jan 11, 2018 at 19:36

1 Answer 1

1

Gzipped content isn't character data -- it's binary data -- which means it can't be directly serialized to JSON. Since the response object is automatically serialized to JSON by callback(), the data needs to be base64-encoded (since base64 of any arbitrary binary data always results in clean character data), and then CloudFront needs to be told what you've done, so it can decode it back to binary and hand it to the browser.

In principle, you need something more like this:

      const response = {
        status: '200',
        statusDescription: 'OK',
        headers: noCacheHeaders, //cachedHeaders,
        body: data.toString('base64'), // assuming data is a buffer here (?), encode it
        bodyEncoding: 'base64',        // tell CloudFront it's base64; CloudFront will decode back to binary
      };

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-generating-http-responses.html#lambda-generating-http-responses-object

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

4 Comments

for a gzipped (in cloudfront) webp image should the 'content-type' be 'image/webp'? when I enabled gzip in cloudfront then it breaks with The Lambda function returned an invalid json output, parsed json should be an object type., I already have what you wrote here except changing it to non cached.. Didn't have the 'statusDescription' either but can't see how it matters..
Seems like you shouldn't gzip images => webmasters.stackexchange.com/a/57590
Fantastic answer! If someone tries to return gzipped compressed data in a Lambda@Edge function in CloudFront triggered by an origin-response event, then that's the way to go. Awesome!
Can you think of any reason why this problem would still be happening despite using your solution? I'm experiencing this for a gif which isn't gzipped. My code is exactly like you posted, yet I get that error.

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.