HTML returned from Lambda#Edge and CloudFront throws JSON is not parsable - amazon-web-services

I'm trying to set up a reverse proxy on a subfolder of our domain (example.com/sub) to show content from a site sitting on a different domain/server. I would like to access that site on the same domain subfolder for SEO purposes.
I have a CloudFront distribution set up for the whole domain. On the same distribution, I have an additional behavior /sub* Viewer request linked to a Lambda#Edge function.
In that lambda function, I'm returning some HTML. For testing, I'm using code straight from AWS docs.
'use strict';
const content = `
<\!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Simple Lambda#Edge Static Content Response</title>
</head>
<body>
<p>Hello from Lambda#Edge!</p>
</body>
</html>
`;
exports.handler = (event, context, callback) => {
/*
* Generate HTTP OK response using 200 status code with HTML body.
*/
const response = {
status: '200',
statusDescription: 'OK',
headers: {
'cache-control': [{
key: 'Cache-Control',
value: 'max-age=100'
}],
'content-type': [{
key: 'Content-Type',
value: 'text/html'
}]
},
body: content,
};
callback(null, response);
};
This works as expected. But when I try to return a more complex HTML for example
exports.handler = async (event, context, callback) => {
console.log(event);
const response = await fetch('https://www.nbcnewyork.com');
const content = await response.text();
const res = {
status: '200',
statusDescription: 'OK',
headers: {
'cache-control': [{
key: 'Cache-Control',
value: 'max-age=100'
}],
'content-type': [{
key: 'Content-Type',
value: 'text/html'
}]
},
body: content,
};
callback(null, res);
};
When I GET the example.com/sub I'm getting the error below.
502 ERROR
The request could not be satisfied.
The Lambda function returned invalid JSON: The JSON output is not parsable. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
Generated by cloudfront (CloudFront)
Request ID: *
In CloudWatch for CloudFront/LambdaEdge I'm also seeing these events:
2022-04-08T12:31:50.000+02:00 (2k-5BGOaTxD_Ll51dVhJbBRN0rQY4yjju4k9TEPQcpgzl1MZa-vYAA==) INFO START processing EventType: viewer-request LambdaFunctionARN: arn:aws:lambda:eu-central-1:*:1 Method: GET URI: /sub
2022-04-08T12:31:50.000+02:00 (2k-5BGOaTxD_Ll51dVhJbBRN0rQY4yjju4k9TEPQcpgzl1MZa-vYAA==) INFO Invoking LambdaFunctionARN: arn:aws:lambda:eu-central-1:*:1 Region: eu-central-1
2022-04-08T12:31:50.000+02:00 (2k-5BGOaTxD_Ll51dVhJbBRN0rQY4yjju4k9TEPQcpgzl1MZa-vYAA==) INFO Response received from Lambda: RequestId: *
2022-04-08T12:31:50.000+02:00 (2k-5BGOaTxD_Ll51dVhJbBRN0rQY4yjju4k9TEPQcpgzl1MZa-vYAA==) ERROR Validation error: The Lambda function returned an invalid json output, json is not parsable.
2022-04-08T12:31:50.000+02:00 (2k-5BGOaTxD_Ll51dVhJbBRN0rQY4yjju4k9TEPQcpgzl1MZa-vYAA==) INFO END processing EventType: viewer-request LambdaFunctionARN: arn:aws:lambda:eu-central-1:*:f
Any ideas about what I'm doing wrong?
Regards, Primoz

Related

Access to fetch blocked by CORS policy: Response to preflight request doesn't pass access control check

I am getting this error when trying to fetch REST API from Amazon Web Services in script defined html file:
Access to fetch at '$(url)' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
script
let body = { token: params.token};
const response = await fetch(
url,
{
method: "POST",
body: JSON.stringify(body),
headers: { "Content-type": "application/json", "Access-Control-Allow-Origin":"*" },
}
);
console.log(response);
const myJson = await response.json();
console.log("response-->", myJson);
if (myJson.statusCode != 200) {
console.log("failed");
return;
}
console.log("success");
return;
}
Running into CORS error
API is deployed with below CORS configurations:
enter image description here
Once you'r done with Cors Console Enable (i see that you already done it on the image).
You need to follow this stepts to setup lambda.
And on your function include headers and response in this way:
const headers = {'Content-Type':'application/json',
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'POST'}
const response = {
statusCode: 200,
headers:headers,
body: JSON.stringify({ token: params.token})
};
return response;
so in your fetch you could call it directly and not await it like this:
fetch(...).then((response) => {
return response.json();
})

Send an ajax request in javascript to AWS API Gateway using raw body

The following body can be successfully sent to an AWS API Gateway, using Body -> Raw in Postman
{
"toEmails": ["foo#example.com"],
"subject": "test email from Postman",
"message": "Hello World!"
}
How do I adjust the following JQuery snippet to send the request to the same API Gateway?
$.ajax({
type: "POST",
url: URL,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
data: JSON.stringify(data),
success: function(res){
console.log('Email was sent.');
},
error: function(res){
console.log(res);
}
});

Issues enabling CORS support for Lambda proxy integrations

I have a lambda function which I've exposed through API Gateway. I'm calling the function with axios. I've not enabled cors on the API Gateway with the OPTIONS method because I'm using lambda proxy integration so I'm sending back the response headers in my lambda function. It works on insomnia but on the browser I'm getting the {message: forbidden} and the error below.
[Error] Preflight response is not successful
[Error] XMLHttpRequest cannot load https://xxxxxxxxx.execute-api.us-east-2.amazonaws.com/production/user/xxxxxxxxxxxxx due to access control checks.
[Error] Failed to load resource: Preflight response is not successful (xxxxxxxxxxxxxxx, line 0)
[Error] Unhandled Promise Rejection: Error: Network Error
(anonymous function)
promiseReactionJob
THE AXIOS FUNCTION
import axios from "axios";
const baseURL =
"https://xxxxxxxxxx.execute-api.us-east-2.amazonaws.com/production/";
import * as apiKey from "./apiConfig";
export const getUser = (username) => {
return axios
.get(`${baseURL}user/${username}`, {
headers: {
"x-api-key": apiKey
},
})
.then(({ data }) => {
console.log(data);
});
};
THE LAMBDA FUNCTION RETURNS
const response = {
statusCode: 200,
body: JSON.stringify(data.Item),
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
};
return response;
EDIT
Following suggestions, I enabled CORS on API Gateway which created the OPTIONS method with the following headers and header mappings. The above error of preflight response is gone. Instead I now receive this error below. I'd also like to note Api Key Required is set to false for the OPTIONS method, however when I set it to true I get the above error again.
{message: forbidden}
https://xxxxxxxxxxxxx.execute-api.us-east-2.amazonaws.com/production/user/xxxxxxxxxxxxxxxxxx
[Error] Failed to load resource: the server responded with a status of 403 () (xxxxxxxxxxxxxxxxxxxxxxx, line 0)
Unhandled Promise Rejection: Error: Request failed with status code 403
Access-Control-Allow-Headers : 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
Access-Control-Allow-Methods : 'DELETE,GET,OPTIONS,PATCH'
Access-Control-Allow-Origin : '*'
I ended up enabling CORS, re-deploying the API Gateway and set all the headers to lambda functions below. It didn't work straight away but after a little while after deploying.
const response = {
statusCode: 200,
body: JSON.stringify(data.Item),
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
};
return response;

Sending http request from aws lambda to google firebse funcitons

I have set up firebase functions to receive http requests and have verified that the same is working. Now im trying to send http request to firebase from aws lambda function. But there is no response either in aws lambda or in the firebase functions log. This is my aws lambda code:
const postData = JSON.stringify({
"queryresult" : {
"parameters": {
"on": "1",
"device": "1",
"off": ""
}
}
});
const options = {
hostname: 'https://<the firebase function endpoint>',
port: 443,
path: '',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, postData)
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log(err);
});
// Write data to request body
req.write(postData);
req.end();
}
The promise part here is suppose to execute the console logs but it is not getting executed. Is there something that i'm missing here. The host is the URL that we obtain when we deploy a function. Or is there some firebase or aws related plan problem. I'am using the spark plan in firebase. Thankyou.

AWS CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. The headers are present

I have been battling with these dreaded CORS issues with AWS for a while now. I thought I had it sorted out and then it turned up again... I have done exactly want I have in the other Lambda functions that work fine.
Why won't it work now?
I have added in the headers in the response to all of the Lambda functions in my handler.js file (I am using serverless to deploy to AWS)
docClient.get(params, function (err, data) {
if (err) {
const response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": true
},
body: JSON.stringify({
message: 'Failed to fetch service request from the database.',
error: err
}),
};
callback(null, response);
}
else {
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": true
}
};
callback(null, response);
}
});
And in the .yml file:
myLambdaFunc:
handler: handler.myLambdaFunc
events:
- http:
path: myLambdaFunc
method: POST
cors: true
I figured out that the problem lies with the docClient.get. I was testing with data where the primary key item being searched for was not in the table.
I wish it didn't tell me that it was a CORS issue because it really wasn't..