express server config:
app.use(
cors({
origin: "*",
methods: "GET,PUT,POST",
allowedHeaders: "*",
exposeHeaders: "*",
optionsSuccessStatus: 200,
})
);
//this fails as well
app.use(cors());
client side request:
let value= await axios({
url: "https://my.api.here.cloud/verifyGroup",
method: "post",
data: data.value,
});
Access to XMLHttpRequest at 'https://my.api.here.cloud/verifyGroup' from origin 'https://my.frontend.here.cloud' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I'm fairly confident it has something to do with AWS resources because in my local environment, these configs allow for cors but as soon as it's up on AWS, I'm getting blocked by cors.
I'm running an ECS Fargate service that's running a single task containing a frontend container and the backend container. Each of these containers has an ALB attached to them.
I came across this post here which gave me some hope, so I tried implementing it into my own solution but it still came up short.
my attempt at implementing the solution from the other post. This is what's being returned at an endpoint:
res.json({
headers: {
"Access-Content-Allow-Origin": "*",
},
statusCode: 200,
body: {
value: true,
},
});
Related
I am trying to point a domain to Github pages site.
I am very new to working with domains and AWS services so I am finding it difficult to troubleshoot issues.
I have created an AWS ApiGateway that points to a lambda function which I would like to use to serve the content from Github pages, but currently, it is giving me the error:
{"message":"Internal Server Error"}
so when trying to fix this issue, I found instructions to make it log additional debug information. (instructions found at: https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-troubleshooting-lambda.html)
this is telling me that my configuration for the lambda function is incorrect.
The response from the Lambda function doesn't match the format that API Gateway expects. Lambda body contains the wrong type for field "headers"
I don't know what is expected so I don't know what needs to be changed... my entire lambda function is configured as:
exports.handler = async (event, context, callback) => {
let domain = 'https://github-org-name.github.io/my-repo-with-gh-pages/';
return {
statusCode: '301',
statusDescription: 'Moved Permanently',
headers: {
'location': [{
key: 'Location',
value: domain,
}],
'cache-control': [{
key: 'Cache-Control',
value: "max-age=3600"
}]
},
}
};
I am completely new to using AWS services, so I don't know if anything else needs to be configured. any help is appreciated.
The values in your headers dict must be strings, e.g:
{
"cookies" : ["cookie1", "cookie2"],
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headername": "headervalue", ... },
"body": "Hello from Lambda!"
}
See the bottom of this page:
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
I have an application written in React JS, running on localhost, which makes API calls to API Gateway in AWS. API Gateway forwards requests to a lambda function, which returns a response. I have enabled CORS on AWS side.
At the moment whenever I click a 'request' button in the application I get a response from the gateway. Here is my current python code:
import json
def lambda_handler(event, context):
response = {}
response['result'] = "Success"
response['message'] = "Updated successfully!"
return {
'headers': {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST'
},
"body": json.dumps(response)
}
And here's the body of the request:
{
"ID": "1101",
"RequestDate": "2021-02-28"
}
This works fine. I get the 'message' value from this response and can display it without problems.
Next I want to display the information containing some data coming from the request. For example instead of Updated successfully I would like to get the RequestDate from the request and return Updated successfully on 2021-02-28.
I added these two lines:
def lambda_handler(event, context):
body = json.loads(event['body'])
request_date = body['RequestDate']
response = {}
response['result'] = "Success"
response['message'] = "Updated successfully!"
return {
'headers': {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST'
},
"body": json.dumps(response)
}
As soon as I make this change I get the following code in my application:
Access to fetch at url from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
This only happens when I add request_date = body['RequestDate']. I tried returning the body only and it was working fine as well.
In my react js application I add following headers as well:
async callAPI(url, method, data) {
let result = await fetch(url, {
method: method,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
data
})
})
return result.json().then(body => this.notify(body['message']));
}
I tried enabling CORS and deploying the resource again but to no avail. I have added Access-Control-Allow-Origin to allowed headers in AWS. As I mentioned it works fine with post method prior to adding that one line. What could be wrong here and how can I remedy it?
EDIT:
One more thing. I get this error only from my application running on localhost. Curling or using any REST client works fine.
EDIT2:
Added fetch code
Setting up CORS in Lambda is dependent on how you setup API Gateway. API Gateway has several modes [REST, HTTP, WebSocket]. In the case of REST, API Gateway does some pre-processing on the incoming request like parameter validation before passing to Lambda. HTTP Proxy is just that, a pass through to Lambda, and Websockets is not really for this discussion.
I am assuming it is because you are using API Gateway in standard configuration and you have not enabled CORS on API Gateway. The code you provided above will work for API Gateway Configured for HTTP.
If you are using the CDK, or CloudFormation then you must configure CORS there, else the easiest is to use the console.
Go to your API in the AWS Console, select resources, select your method or service, from the actions menu enable CORS. And then publish your updated API.
Here is a link to the AWS documentation that outlines how to do it.
Some advice, when testing endpoints via a browser it is best not to use Localhost or 127.0.0.1 it has unintended consequences. Edit your hosts file and give yourself a domain name, and use that domain name instead.
CORS is there for a reason to prevent Cross Site Scripting or Cross Site Origin Attacks. Try not to use *, testing sure, but production no. If you have code say on S3, and your REST services on say API Gateway you can front both with CloudFront using the same Origin, and let CloudFront know to forward based on URL (e.g /API) to APIGateway and the other to S3. Thus everything has the same domain.
This is what I have on my server and it works fine. Using fetch on the front-end.
Server Code:
import json
result = {"hello": "world"}
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*"
},
'body': json.dumps(result)
}
Front-end Code using ES6
url = "Your url"
path = "Your desired path"
data = {"hello": "world"}
const response = await fetch(url + path, {
method: "POST",
cache: "no-cache",
mode: "cors",
body: JSON.stringify(data),
});
Add statusCode inside response from lambda
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST'
},
'body': json.dumps(response)
}
In case there is any error in your lambda it will return default 5XX response without any CORS headers and in such cases browser will complain for cors headers not found.
You can add your current code in try block and in except block you can print the error and return some default response like below
return {
'statusCode': 500,
'headers': {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST'
},
'body': json.dumps({'message':'Unexpected error'})
}
Add some log statements in your lambda and check api gateway configuration for Lambda proxy setting.
Make sure you check your api gateway logs and lambda function logs for some more details regarding error.
I'm trying to upload files to Google Cloud Storage (GCS) from the client browser. For that I have a back-end in node.js request a Signed URL from GCS, which is then transmitted to the front-end client to upload the file. The Signed URL request code is the following:
const options = {
version: "v4",
action: "write",
expires: Date.now() + 15 * 60 * 1000, // 15 minutes
contentType: content_type,
};
// Get a v4 signed URL for uploading file
const [url] = await storage
.bucket(bucketName)
.file(filename)
.getSignedUrl(options)
This is working. The issue comes when I try using the Signed URL on the client. Every request ends up with the following error:
Access to XMLHttpRequest at 'https://storage.googleapis.com/deploynets_models/keras_logo.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=urlsigner%40deploynets.iam.gserviceaccount.com%2F20200711%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200711T192805Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=82b73435e4759e577e9d3b8056c7c69167fdaac5f0f450381ac616034b4830a7661bdb0951a82bf749a35dc1cf9a8493b761f8993127d53948551d7b33f552d118666dcf8f67f494cfaabf2268d7235e955e1243ce3cd453dcc32552677168ad94c6f1fca0032eb57941a806cc14139915e3cd3efc3585497715a8ad32a1ea0278f2e1165272951ae0733d5c6f77cc427fd7ff69431f74f1f3f0e7779c28c2437d323e13a2c6474283b264ab6dc6a94830b2b26fde8160684839a0c6ea551ca7eff8e2d348e09a8c213a93c0532f6fed1dd167cd9cf3480415c0c35987b27abd03684e088682eb5e89008d33dcbf630b58ea6b86e7d7f6574466aa2daa982566' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've set the CORS policy on the GCS bucket with the following JSON:
[
{
"origin": ["*"],
"method": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"responseHeader": ["*"],
"maxAgeSeconds": 120
}
]
(I've also tried listing specifically the origin as http://localhost:3000 for example)
It should be mentioned that I have got it to work in one specific case: when the upload payload is just a plain string. For some reason it works fine then.
I've looked up online all the similar errors I could but to no avail so far. Any idea?
Update: Finally got it to work! I had to add contentType: 'application/octet-stream', and processData: false, for it to work. Otherwise I was getting the errors:
CORS error Access to fetch at 'https://storage.googleapis.com/...' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Uncaught TypeError: Illegal invocation and Uncaught (in promise) TypeError: Failed to execute 'arrayBuffer' on 'Blob': Illegal invocation
So final AJAX request looks like this (working):
$.ajax({
url: <GCS signed upload URL>,
type: 'PUT',
data: f, //file object
contentType: 'application/octet-stream', //seems to be required
processData: false, //seems to be required
})
I also had to set the bucket CORS using the command:
gsutil cors set gcs_cors.json gs://<my_bucket>
The file gcs_cors.json contents were:
[
{
"origin": ["https://<myapp>.appspot.com", http://localhost:8080"],
"responseHeader": ["Content-Type"],
"method": ["GET", "HEAD", "DELETE", "PUT", "POST"],
"maxAgeSeconds": 120
}
]
Original post: I am not sure how this worked for you (happy it did though!), I have tried using the file directly and using Form Data but it was not working. Uploading to GCS seems to be quite a frustrating process. I was hoping the documentation would have a complete working example (front-end/back-end) but it doesn't seem to be the case.
I figured out what was wrong. In the upload code (browser side), I was passing a FormData object as the data to be uploaded, which for some reason was triggering the CORS error above. I fixed it when I passed the file directly.
So instead of using the following:
var data = new FormData()
data.append('file', event.target.files[0])
I use directly the file in event.target.files[0].
I was facing the exact same issue and there was a problem with the options that I was passing, try changing the options to
const options = {
action: "write",
expires: Date.now() + 15 * 60 * 1000, // 15 minutes
}
this solution worked for me.
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..
I have a react application linked to a Django backend on two separate servers. I am using DRF for django and I allowed cors using django-cors-headers. For some reason when I curl POST the backend, I am able to get the request out. However when I use axios POST the backend, I get and error. The status of the POST request from axios is failed. The request and takes more than 10 seconds to complete. My code was working locally (both react and django codes), but when I deployed to AWS ec2 ubuntu, the axios requests stopped working.
Console error logs
OPTIONS http://10.0.3.98:8000/token-auth/ net::ERR_CONNECTION_TIMED_OUT
{
"config": {
"transformRequest": {},
"transformResponse": {},
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8",
"Access-Control-Allow-Origin": "*"
},
"method": "post",
"url": "http://10.0.3.98:8000/token-auth/",
"data": "{\"username\":\"testaccount\",\"password\":\"testpassword\"}"
},
"request": {}
}
Here is my request code
axios.post('http://10.0.3.98:8000/token-auth/',
JSON.stringify(data),
{
mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : '*'
},
},
).then( res => (
console.log(JSON.stringify(res)),
)
).catch( err => (
console.log(JSON.stringify(err))
)
);
my curl code that worked
curl -d '{"username":"testaccount", "password":"testpassword"}' -H "Content-Type: application/json" -X POST http://10.0.3.98:8000/token-auth/
UPDATE 1
on firefox i am getting the warning
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://10.0.3.98:8000/token-auth/. (Reason:
CORS request did not succeed).[Learn More]
UPDATE 2
Perhaps it has something to do with my AWS VPC and subnets? My django server is in a private subnet while my react app is in a public subnet.
UPDATE 3 - my idea of what the problem is
I think the reason why my requests from axios aren't working is because the requests i'm making is setting the origin of the request header to http://18.207.204.70:3000 - the public/external ip address - instead of the private/internal ip address which is http://10.0.2.219:3000 - i search online that the origin is a forbidden field so it can't be changed. How can i set the origin then? Do I have to use a proxy - how can I do that.
try this http request instead of axios, it's called superagent (https://www.npmjs.com/package/superagent) , just install it to your react app via npm,
npm i superagent
and use this instead of axios.
import request from 'superagent'
const payload ={
"1": this.state.number,
"2": this.state.message
}
request.post('LINK HERE')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send(payload)
.end(function(err, res){
if (res.text==='success'){
this.setState({
msgAlert: 'Message Sent!',
})
}
else{
console.log('message failed/error')
}
});
The issue here is that the request is being made on the client browser. You need to either use a reverse proxy or request directly to the api server. You cannot do a local ssh forwarding either.