Open nicksemansonos opened 3 years ago
Hi @nicksemansonos, thank you very much for the detailed report. This is indeed interesting. Are you positive that NextJs should be gzipping the content of SSR pages? Running it locally may not be an accurate comparison with the deployed version as their local server may behave differently than a production build.
Their documentation suggests that you should enable this on your proxy to offload the load from NodeJS: https://nextjs.org/docs/api-reference/next.config.js/compression. In this case your proxy would be CloudFront but as I understand your description, the problem is that the Lambda@Edge is returning the response uncompressed which is what causes the payload limit to be exceeded.
We are going to look into this closer, but glad to hear that there is a workaround to gzip the content yourself even though is not an ideal solution. Thanks for reporting and let us know if you find additional information.
@ferdingler Any update on this one. We are having a very similar problem with Amplify using NextJS SSR backed by WP Graphql and certain larger pages tend to throw the 502 error described by @nicksemansonos above.
Since our pages are dynamic it is harder for us to add GZIP to a specific API endpoint. Hoping there has been some traction on this issue.
Thanks.
Before opening, please confirm:
App Id
d2icpnoec5rp5b
Region
us-east-1
Amplify Console feature
Not applicable
Describe the bug
We noticed that one of our SSR API routes (defined in the /pages/api directory of our Next.js app) was 502ing in production (Amplify to Lambda@Edge,) but working as expected running locally. With a bit of research and viewing the logs, we discovered that this was because the response was over CloudFront’s 1MB limit for “Size of a response that is generated by a Lambda function, including headers and body.”
This was strange though, because even though the uncompressed size was 1.01MB locally, the actual response size was around 241kb. This is according to the network inspector in the browser. This difference makes sense, Next.js uses gzip internally to compress the responses to save space. If CloudFront was receiving this 241kb response from the Lambda function, it shouldn’t be failing for being too large.
Other responses from the same route (with different parameters) were coming back from Lambda@Edge with gzip compression. It would appear that CloudFront is not accepting the gzip compressed response of the Lambda function, and is either bypassing the internal Next.js gzip, or is uncompressing the response before processing it. Then, before it is sent as a final response, it is applying its own gzip compression again.
Expected behavior
Since the final compressed response was under 1MB, we expected this route to work without hitting the size limitation.
Reproduction steps
In our case, we are processing a large number of Salesforce records and returning the result as JSON. The uncompressed response was 1.01MB but compressed it was 241KB. This caused the error, even though 241KB is well within the 1MB limit.
Build Settings
No response
Additional information
Workaround
On the problematic API route, I manually added gzip compression to the response by using the zlib library and setting the Content-Encoding header to “gzip”. Even though Next.js usually does this part on its own internally, I suspected that doing it manually would “force” CloudFront to accept the gzipped version of the response, which would be within the size limitation.
Before deploying, I tested the workaround locally and was happy to see that it worked exactly as expected. The network inspector showed the same response size and uncompressed size as before, even though now I was manually adding the gzip compression. This means that Next.js luckily didn’t “double compress” the response, which was exactly what we needed.
So it was time to deploy to Amplify. We were pleasantly surprised to find that the API route now worked perfectly! Even though the uncompressed size was still over the 1MB limit, the response being sent to CloudFront was well under the limit, and so it was processed successfully. CloudFront also must have noticed it was already compressed with gzip, so it also did not “double compress” the response. This also suggests that CloudFront wasn’t uncompressing the response from the Lambda first, because that would have happened here too.
Luckily, this is our only API route that comes close to the size limit, so we don’t need to manually re-add gzip compression to everything. That would be a pretty tedious “solution” to the issue at hand.
Conclusion
It seems like if Lambda didn’t ignore/bypass the native gzip compression of Next.js, it could process much “larger” response payloads that are still well within the 1MB limit, provided they are compressed with Next.js internal gzip before CloudFront has to handle it.
In conclusion, the 1MB Lambda@Edge response limit in a Next.js SSR Amplify project currently effectively applies to the uncompressed size, even though the actual final response size will still be compressed with gzip and might well be under the 1MB limit. At the very least, this limitation should be clarified in the Amplify, CloudFront, or Lambda@Edge documentation.