API Gateway CORS issue, with correct payload - ajax

I've been trying to fix this all day.
I got a Lambda function I'm trying to run when I make a POST request to the endpoint (configured with AWS API GATEWAY).
Everything runs fine, my options gets a 200 okay, my post gets a 200 okay and comes back with the data I want.
However when I get it back, it "thinks" it failed. I use JQuery for this project, and it comes back as the "fail" cb.
Looking at the console log the problem is quite clearly the following error:
XMLHttpRequest cannot load
https://xxxxxxxxx.execute-api.us-west-2.amazonaws.com/prod/createCustomer.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
a standard CORS issue. But nothing I do seems to work. I enabled CORS on the API gateway (before that the OPTIONS would fail). the 'Access-Control-Allow-Origin': is set to: '*' which should allow access from any origin. I of course deployed the new API.
I also tried not using CORS and instead enabling the AWS proxy thing, and having my response like this { statusCode, headers, body } but when doing that I get no response whatsoever.
I have absolutely no clue where to start attempting to fix this. I even tried a dirty jsonp method. But still same problem. :(
The only bit of data I can find on my request that doesn't seem okay, is this: x-cache:Miss from cloudfront
Here's the full response headers from the POST request:
content-length:2312
content-type:application/json
date:Thu, 23 Mar 2017 22:15:08 GMT
status:200
via:1.1 95a477af435073615179b256d8101334.cloudfront.net (CloudFront)
x-amz-cf-id:Hc6POYFO0HKB1xriSg2iH7O1po7ah926a4dQkgfSNBUZ460RoHRNuw==
x-amzn-requestid:2b5ed745-1016-11e7-b497-cb0a77cd1479
x-amzn-trace-id:Root=1-58d448ea-56717776eaa3f5389083e9ca
x-cache:Miss from cloudfront
Sadly as is quite obvious, the Access control headers aren't there... I assume that's the problem I'm desperately trying to fix. But I have no idea why since I set it to ' * ' during the Enable CORS step of this process.
I was able to get semi-close to a solution by manually creating a POST method (as opposed to "ANY"), then enabling CORS again, then turning on the PROXY on integration response, and set my response to: { statusCode, headers, body } This will come back as a successfull event and run the right callback function in my ajax call. However, using this method I get no data back from Lambda... despite having it in "body", all I receive is an empty object.
I don't really have a preference of using CORS or manually adding headers, that's fine I won't be updating this much. I just really really need to get it functioning :( Any help would be greatly appreciated.

If you got x-cache:Miss from cloudfront from your API, it is fine because API Gateway doesn't enable the edge cache on the cloudfront side. If you want CORS to work with Lambda proxy integration, you can return the status code and the headers, like,
{
"statusCode": 200,
"headers": { "Access-Control-Allow-Origin": "<domains you need>" }
}
Then, it will be like an empty response from the client side.

I have now idea why, but I was able to get it working. Using the following steps:
Enable CORS,
Deploy API, (can probably be skipped...)
Manually add POST method,
Enable Proxy on Integration response,
Deploy API again
change callback response to format: { statusCode: 200, headers: {}, body: {} }
use JSON.parse() to parse your payload.
This is definitely not a perfect answer. For some reason turning on the Proxy modified how my Lambda function received data, so I had to Stringify it to not cause an error. I can't offer an explanation why this happened.
The headers I used were:
"Access-Control-Allow-Methods": "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT",
"Access-Control-Allow-Origin": "*"
A better solution to this would also be a way to do this just using CORS. As you don't have to manually insert headers in all your responses. But I couldn't get that working. So please, if someone knows a better solution to this post it!

Related

AWS API gateway really works well but I can't run this on javascript AJAX

I made python function using AWS lambda and connected lambda with API Gateway
After then, I tested API. It worked well.
Testing in API Gateway was Successful
Now I tried to using this API with AJAX.
Javascript AJAX Code was like this
How ever result was
"jquery-3.4.1.js:9837 GET https://9i1jhuewmj.execute-api.ap-northeast-2.amazonaws.com/test/transaction?jpgname=image.jpg net::ERR_FAILED"
How can i solve this problem??
Hope for your wisdom!
Thank you
I think there are a few things. The content-type header being returned is application/json but the response is not JSON.
But I think the main problem is that the HTTP status being returned is 301. This tells the browser that this resource has been moved and the browser typically expects the response to contain information on where things are moved to so it can redirect.
I suspect if you change your configuration so that a more normal response code (i.e. 200) is returned, this will work better.

read ALL response headers of ajax GET request of S3 objects

Question Overview:
I am accessing a list of files stored in my AWS S3 bucket through a CORS request of presigned files. This basically works fine. However, the objects have some custom METADATA attached to them, which I can't access. I understood, that I can access this metadata only when I add the header key (e.g. "x-amz-meta-1234", where 1234 is the key of my metadata) to the Expose-Headers of the target-bucket's CORS config. While this works so far for me, I can't set the expose-header with a wildcard (e.g. "x-amz-meta-*"), which would solve my problem, but AWS doesn't support wildcards for the expose-header entries.
However, when I look in the NETWORK tab of my Chrome Dev Tools, all desired metadata is showing up in the headers during the GET/HEAD request (note the entries on the lower part, x-amz-meta-4021 and -template_id):
This is my HEAD call:
$.ajax({
url: url,
dataType: 'json',
crossDomain: true,
type: 'HEAD',
success: function(data, status, jqXHR) {
console.log('got some response ..?');
console.log(data);
console.log(jqXHR);
console.log('responseHeader template_id: ' + jqXHR.getResponseHeader('x-amz-meta-template_id'));
console.log('responseHeader meta-4021: ' + jqXHR.getResponseHeader('x-amz-meta-4021'));
console.log(jqXHR.getAllResponseHeaders());
},
error: function(error, xhr, data) {
console.log('in error..');
console.log(error);
console.log(xhr);
console.log(data);
}
});
});
And this is the console output:
Object {readyState: 4, getResponseHeader: function, getAllResponseHeaders:
function, setRequestHeader: function, overrideMimeType: function…}
responseHeader template_id: 813
responseHeader meta-4021: null
x-amz-meta-template_id: 813
Last-Modified: Fri, 09 Jun 2017 13:05:33 GMT
Content-Type: video/mp4
I set expose-header for the metadata-entry 'template_id' explicitly and therefore the header-data is returned correctly for this entry. However, for the entry '4021' I didn't set the expose-header. The problem is, that this metadata (and the keys) are produced by our (android/ios) apps, and I can't really control the keys of that metadata that easily.
Whats puzzling me: why am I able to see the whole response in the chrome network tab, but can't access this data from a client-side script? There are many possible workarounds and solutions, but I basically want to understand, why my browser can display me data, which can't be accessed by jQuery.
PS: in case you want to see the CORS config or the full script, please let me know. I tried to be as precise as possible. Thanks in advance!
I basically want to understand, why my browser can display me data, which can't be accessed by jQuery.
To understand this, you need to understand the purpose of CORS.
CORS isn't really about access control, and CORS isn't really working on your site's behalf. CORS is working on behalf of the user and the browser, to prevent the browser from becoming a confused deputy and doing something the user would not have wanted. This usually coincides with something the site would also not have wanted, but that's secondary.
The browser's default behavior is to assume that programmatic access to cross-origin requests is bad, which is why they are denied when no Access-Control-Allow-Origin header is present. Your bank would not want internetbadguys.com to make ajax requests to the bank web site, and if that site tried, the browser would block it unless the bank's web server foolishly allowed it with a CORS response.
CORS is a mechanism for your site to tell the brower, "yes, the cross-origin request you are making is not unexpected, it's allowed... and from this response, the browser is allowed to engage in certain behaviors, such as exposing the following response headers to the code making the request."
In that light, the behavior you observe is correct. Exposing headers (or not) doesn't mean include them in the HTTP response (or not) -- exposing headers gives the browser permission to expose what it knows to the ajax caller. If the cross-origin origin wants them exposed, it has to be explicit.

POST request to AWS API Gateway access

I have a AWS Lambda function that is triggered via AWS API Gateway. When I test my function on Lambda it is working. When I send a POST request to the API url via ajax, I get a 502 bad gateway error.
XMLHttpRequest cannot load https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/prod/myLambdaFunction. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'mywebsite.com' is therefore not allowed access. The response had HTTP status code 502.
Obviously this was a CORS issue, so I thought I could change the CORS settings in my AWS API Gateway URL which I did, but I am still getting an error for this.
What do I have to change on AWS side or my own to be able to POST to the URL?
Unfortunately there is a known issue with many classes of 4xx and 5xx errors where CORS headers will not be sent, even if you've added CORS support via the console.
As noted in comments, the CORS error is a side effect of the fact that your API is returning a 502. This often occurs if you are using the LAMBDA_PROXY integration type and are returning invalid JSON from your Lambda function.
Please try either using the test invoke functionality from the console or enable logging in your API to debug further.
I solved that exact same problem by outputting the CORS header myself.
See below - and I hope that'll help.
Teebo
Amazon docs
function respond(context, responseData) {
var response = {
statusCode: 200,
body: JSON.stringify(responseData),
headers: {
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Origin": "*"
}
};
context.succeed(response); }

Sencha Touch and CORS request not working

I'm trying to implement a login service on a Web app using Sencha Touch.
I already have a REST service working properly (I can test it using chomr extension Dev HTTP Client).
Now, the request is an Ajax request after doing some research, I've found out that cross-domain requests are protected, according to CORS.
I modified my Ajax client, adding:
useDefaultXhrHeader: false
when constructing the Ajax request, and I added to the headers:
Access-Control-Allow-Headers: x-requested-with
Access-Control-Allow-Origin: *
in my response.
Still using the Dev HTTP Client, I can now see my headers correctly set in the response.
But, in my app, I keep getting the error:
No 'Access-Control-Allow-Origin' header is present on the requested resource
If I use the --disable-web-security parameter when launching Chrome, everything works as it should, headers are sent (or at least, they are not blocked anymore by Chrome), but obviously, this is not the proper way to do it.
Can someone help me out on this?
Please follow the link http://enable-cors.org/server_apache.html and enable cors on your server. You client ajax request is correct but you still need enable cors on the server.

Ajax POST,PUT,DELETE problems with CORS but not every time

we are using CORS Filter to send AJAX request between two different domains and we set the configuration properties of this filter by code using OSGI HttpService instead of a web.xml file. The problem is that sometimes (not every time) it doesn't work correctly, it doesn't let us make POST, PUT or DELETE requests. We have add the property xhrFields:{withCredentials: true} to these requests but it hasn't change anything.
We have tried to make these requests with Google's Simple Rest Client and we have observed that even when our website is forbidden to perform this request Google's Client always has access.
Does someone know how we can solve it?
On the server side, try adding the following header:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS

Resources