The question is: Why is not possible to change http status before return responses in ViewerResponseEvents in lambda edge?
I have a Lambda function that must check every single response and change it's status code based on JSON file that I have in my lambda function. I deployed this lambda function in Viewer response because I want that this function executes before return every single response. Aws Documentation ( https://aws.amazon.com/blogs/networking-and-content-delivery/lambdaedge-design-best-practices/ ) says if you want to execute a function for all requests it should be placed in viewer events.
So, I've created a simple function that basically is cloning and changing the http status code of response before return it. I did this code for test:
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
console.log(request);
console.log(`Original response`);
const response = event.Records[0].cf.response;
console.log(`Original response`);
console.log(response);
//clone response just for change the status code
let cloneResponseReturn = JSON.parse(JSON.stringify(response));
cloneResponseReturn.status = 404;
cloneResponseReturn.statusDescription = 'Not Found';
console.log('Log Clone Response Return');
console.log(cloneResponseReturn);
return cloneResponseReturn;
};
When I access the log in cloudwatch, it shows that response has http 404 code, but for some reason, cloudfront still returning the response with 200 status code. (I've cleared browsers cache, tested it in other tools such as postman, but in all of them CloudFront returns HTTP 200)
CloudWatch Log and Response print:
If I change this function to execute in origin response it will work, but I don't want to execute it ONLY in cache miss (+as aws tell us that origin events will be executed only in that case+). As origin events are executed only in cache miss, to execute that redirects I would have to create a chache header buster to make sure that origin events will be always executed.
Is really weird this behaviour of edge lambda. Does anyone have any idea how I can solve this? I already tried to clean cache of browsers and tools that I am using for test the requests, also clean the cache of my distribution but still not working.
I've posted the question in AWS Forum a week ago but it still without answer: https://forums.aws.amazon.com/message.jspa?messageID=885516#885516
Thanks in advance.
Related
I am using ALB as a trigger for lambda function, when I post request to the alb, I can see the trigger request in cloud watch, however, there's no response to the post request I posted using postman.
I added logs in the code to check it enters the lambda or not but I can't see python logs. Also, I added a role with ElasticLoadBalancingFullAccess to lambda. but still no response; I am not sure how to debug or move on further I tried multiple things, I even added context.done(respons) to the lambda handler, I also changed the format to be json format returns the status code and the body. Any insights will be appreciated.
EDIT:
details about ALB:
listeners: port 80
target: lambda type and I choose my lambda function
security group: simple security groups allow public access (it works fine as I am triggering the lambda by the request)
lambda code:
def lambda_handler(event,context):
# Initialize you log configuration using the base class
context.succeed({
'statusCode': 200,
'body': json.dumps("wuccedd")
})
also I noticed when I put an error intentially in the lambda function like this forexample:
def lambda_handler(event,context):
#error
x= 10/0,,,,,
context.succeed({
'statusCode': 200,
'body': json.dumps("wuccedd")
})
and this also kept the request stuck, which means it doesn't enter the handler function, any idea why the function can be triggered in cloud watch but the handler function isn't entered
My function takes about 1-2 min to execute while API gateway has 30 second timeout. To overcome this I followed AWS documentation and enabled InvocationType:Event header. The issue is that I receive 200 response after execution, but how do I receive my output? I can see lambda output in cloudwatch but what happens to it next?
Code used for making request
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "https://my-endpoint.com", true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("InvocationType", "Event");
xhttp.send("foo");
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText); //no output here
}
};
If I send a synchronous request by removing InvocationType header then I get desired result.
When dealing to asynchronous functions, you have two ways out:
Use a callback url: on your first request, you pass as parameter (or previously configure) a callback url that your function will call when have the result. This is the most efficient way and widely used on many APIs. It's also called web hook
Store your lambda function response anywhere and your api client must pool for results. This is not so efficient because you will need to do multiple requests until the lambda function finishes, increasing your costs.
The flow on the first method is like:
Hey API, do my long duration task, and when ready call me back on https://sample-domain.com/callback-url
API processes the task, and access the given callback url with the result as payload
The client receives the callback request and processes the result as desired.
There's some security concerns here: someone can discover your callback url and try doing requests to fake something or just trying to DDoS attack.
To mitigate this possibility, you can use random urls for the callback, adding something that identifies the original request.
I am unable to map error from lambda to Status Code 400.
My lambda code in Go is as follows
package main
import (
"errors"
"github.com/aws/aws-lambda-go/lambda"
)
func main() {
lambda.Start(returnError)
}
func returnError() error {
return errors.New("Something went wrong!")
}
I have added Response Integration to Status Code 400 as follows.
Still I get response Status Code 200 as follows. I want it to be 400
I am already using mapping template for request and response. I want to separate Lambda from mapping & validation.
You need to setup Lambda as Proxy integration and then write to return status code from lambda as 400.
Here is an existing post:
Is there a way to change the http status codes returned by Amazon API Gateway?
I have been trying to get the response from API gateway, but after countless tries and going through several online answers, I still wasn't able to solve my issue.
When I test my POST method for the API, it gives me proper response on lambda test and API gateway method test, but when I try it from my react app, it doesn't return the same output.
My lambda snippet:
const response = {
statusCode: 200,
body: JSON.stringify({payload: {"key": "value"}})
};
return response;
But the response I am getting using fetch API on my react app:
I am new to AWS and would appreciate if someone point me in the right direction.
So the fetch API allows you to receive responses as a readablestream, which is what it shows you are receiving in that image there. This resource here, should be helpful in how to properly handle the response.
There are also many other commonly used libraries like axios that are primarily promise / callback driven and you won't have to worry about streams too much unless you want to. You should be able to get fetch working with promises too, but I've never done it myself.
In general, streams are really useful when you have a large amount of data and receiving it all at once in a giant chunk would be really slow, cause timeouts, etc.
I'm new to AWS Lambda and Lambda Edge and I'm trying to understand the purpose. In Lambda Edge I see in the promo page it kind of implies Edge is a middleware in that you can modify the request.
I see in the nodejs examples that to continue processing of a request you can use callback(null, request); but whenever I use that I get a 502 response.
For example can I add/modify a header and then continue a request to a Cloudformation or API Gateway backend or must the lambda return an object of some sort?
Here is an example (logs show header is added and all is well, just that curl returns 502):
exports.handler = (event, context, callback) => {
console.log(context);
console.log(event);
const request = event;
request.headers.bar = 'foo';
console.log(event);
callback(null, request);
};
One of the issues that sometimes stumps people when trying to use Lambda#Edge is that testing your script successfully in the Lambda console only tests whether your code can run without throwing exceptions.
What it doesn't test for is whether your test event looks like a test event that CloudFront would generate, or whether your returned values would actually be interpreted as valid by CloudFront.
The event you are passed is a complex object containing one record, and inside there is cf (CloudFront) which contains request. If you are a response trigger, it also contains response.
See Lambda#Edge Event Structure. There are test event templates in the Lambda console for various types of CloudFront interactions.
So you need to get the original event's request from the right part of the structure:
const request = event; // incorrect
const request = event.Records[0].cf.request; // correct
Headers are confusing at first, but this is actually an example of very sensible engineering design. HTTP headers are not case sensitive in HTTP/1.x and are always lowercase in http/2, but JavaScript object keys are always case sensitive... so a sensible representation of headers takes all of these factors into account, as well as the fact that some headers can appear more than once and the ordering can be relevant.
In headers, the object key is always lowercase, and each value is an array of objects that contains a key (which must match the outer key, except for lettercase) and a value (the header).
request.headers.bar = 'foo'; // incorrect
request.headers['bar'] = [ { key: 'Bar', value: 'foo' } ]; // correct
Additionally, certain headers are blacklisted -- for reasons of security or simple sanity, you can't add or manipulate them.
See Headers in the Lambda#Edge section of the CloudFront Developer Guide.
Also, remember that CloudFront is a cache, and caches have cache keys -- the unique value that identifies a specific request, so that other, identical requests can be determined to actually be identical and served with the same response. The cache key in CloudFront consists of only what CloudFront is configured to send to the origin -- which does not include headers that you haven't whitelisted for forwarding to the origin in the Cache Behavior settings. Trying to set or modify a header inappropriately will result in a 502 error. In the example above, you would need to whitelist the Bar header for forwarding to the origin, in the cache distribution settings.
You might find it initially easier to learn by trying to modify a response, rather than a request, because they are somewhat more forgiving.
Note that in request triggers, you have essentially four possible outcomes:
leave the request unmodified and return control to CloudFront by using return callback(null, request); without changing anything
modify the request by modifying the request object and then `return callback(null, request);
stop further CloudFront processing, and generate a response directly by building a valid response object and calling return callback(null, response);
throw a hard exception by setting the first callback() response to something other than null
In a viewer request trigger, generating a response returns the response to the viewer without checking the cache and without caching the response.
An origin request trigger only fires after the cache has already been checked, and the object is not there. If you generate a response in an origin request trigger, the response is stored in the cache and returned to the requester. The request is never sent to the origin if you generate a response in this trigger. If you modify the request, it is sent to the origin and the response is cached unless configured not to be cached.
An origin response trigger modifies or replaces the response from the origin, and the modified response is stored on the cache.
A viewer response trigger modifies or replaces the response that was either fetched from the cache or from the origin. The modified response is not cached.
Response triggers are also able to inspect the original request, in cases where this might be desirable.