I am using the serverless framework to deploy my lambda to AWS and have been able to successfully run POST requests via Postman to the API Gateway associated with my lambda function, but when I try run a POST request from a form submission (AJAX request) on a local server I am receiving the 502 error message,
Access to XMLHttpRequest at 'https://*id*.execute-api.us-east-1.amazonaws.com/prod/message' from origin 'http://localhost:2368' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
which I didn't expect since I have the cors property in my serverless.yml set to true, which sets CORS configurations for the HTTP endpoint. Here is the function yaml setup:
functions:
email:
handler: handler.sendEmail
events:
- http:
path: message
method: post
cors: true
Here is the jQuery AJAX request:
$.ajax({
type: 'POST',
url: 'https://*id*.execute-api.us-east-1.amazonaws.com/prod/message',
crossDomain: true,
data: JSON.stringify(formData),
contentType: 'application/json',
dataType: 'json',
success: function(data) {
console.log(data)
},
error: function(xhr, ajaxOptions, thrownError) {
console.log(xhr);
console.log(ajaxOptions);
console.log(thrownError);
}
});
Is there something that I need to adjust with the API Gateway configuration or within my Lambda application?
Here is my response function:
const generateResponse = (body, statusCode) => {
console.log("generateResponse")
console.log(body)
return Promise.resolve({
headers: {
"access-control-allow-methods": "POST",
"access-control-allow-origin": "*",
"content-type": "application/json",
},
statusCode: statusCode,
body: `{\"result\": ${body.message}}`
});
};
Also provided is the ajax request:
$.ajax({
type: 'POST',
url: 'https://*my-lambda-id*.execute-api.us-east-1.amazonaws.com/prod/message',
crossDomain: true,
data: JSON.stringify(formData),
contentType: 'application/json',
dataType: 'json',
success: function(data) {
console.log(data)
},
error: function(xhr, ajaxOptions, thrownError) {
console.log(xhr);
console.log(ajaxOptions);
console.log(thrownError);
}
})
And the resulting OPTION and POST Request and Response Headers triggered by the AJAX:
OPTIONS:
Request URL: https://*my-lambda-id*.execute-api.us-east-1.amazonaws.com/prod/message
Request Method: OPTIONS
Status Code: 200
Response Headers
access-control-allow-credentials: false
access-control-allow-headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent
access-control-allow-methods: OPTIONS,POST
access-control-allow-origin: http://localhost:2368
content-length: 1
content-type: application/json
date: Tue, 08 Oct 2019 11:11:36 GMT
status: 200
via: 1.1 *id*.cloudfront.net (CloudFront)
x-amz-apigw-id: *id*
x-amz-cf-id: *id*
x-amz-cf-pop: *id*
x-amzn-requestid: *id*
x-cache: Miss from cloudfront
Request Headers
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Origin: http://localhost:2368
Referer: http://localhost:2368/
Sec-Fetch-Mode: no-cors
POST
Request URL: https://*my-lambda-id*.execute-api.us-east-1.amazonaws.com/prod/message
Request Method: POST
Status Code: 502
Request Headers
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/json
Origin: http://localhost:2368
Referer: http://localhost:2368/
Sec-Fetch-Mode: cors
Wherever you return a response from your Lambda function you need to include the specific header CORS requests. The cors: true option you add to serverless.yml only helps make sure that the OPTIONS pre-flight requests work. Don't forget that this includes non-success responses as well.
For example:
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Headers': 'Authorization'
}
}
Related
I have configured a serverless function as below
id:
handler: id.get
events:
- http:
path: id
method: get
cors:
origin: ""
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- x-access-token
allowCredentials: true
Code in my handler function is as below
let headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': event.headers.Origin ? event.headers.Origin : event.headers.origin,
'Access-Control-Allow-Credentials': true
}
callback(null, {
"isBase64Encoded": false,
"statusCode": 200,
"headers": headers,
"body": JSON.stringify(body),
"multiValueHeaders": multiValueHeaders
})
I am getting response to OPTIONS request as
access-control-allow-origin: *
access-control-allow-credentials: true
Due to that I am getting the below error
Access to XMLHttpRequest at 'https://example.com/dev/id' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I want the Access-Control-Allow-Origin should be dynamic(origin of the request), How can I fix the issue?
I have created a new method options with the below code
module.exports.options = async (event, context, callback) => {
const origin = event.headers.Origin || event.headers.origin;
context.succeed({
headers: {
"Access-Control-Allow-Headers": "Accept,Accept-Language,Content-Language,Content-Type,Authorization,x-correlation-id,x-access-token",
"Access-Control-Allow-Methods": "GET,HEAD,OPTIONS",
"Access-Control-Allow-Origin": origin ? origin : '*',
"Access-Control-Allow-Credentials": true
},
statusCode: 204
});
};
serverless.yml
options:
handler: id.options
events:
- http:
path: id
method: options
Change to this config:
id:
handler: id.get
events:
- http:
path: id
method: get
cors:
origin: "*"
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- x-access-token
allowCredentials: true
Laravel Version: 5.3.31
Description:
I have the exact same ajax call on two diferente pages of my project but im getting an "methodNotAllowed" error in one of them.
My web.php:
Route::post('/seccion', 'FiltrosController#getSecciones')->name("filtro.secciones");
My AJAX call:
$.ajax({
type: "post",
url: "{{ route("filtro.secciones") }}",
data: $("#form").serialize(),
dataType: "json",
success: function (datos) {
//mycode
},
error: function (request, status, error) {
console.log(error);
}
});
Here is the header of the call that works:
Request URL:http://192.168.99.100:3001/seccion
Request Method:POST
Status Code:200 OK
Remote Address:192.168.99.100:3001
Referrer Policy:no-referrer-when-downgrade
And the response header that i get:
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:457
Content-Type:application/json
Date:Mon, 07 Aug 2017 19:26:43 GMT
Keep-Alive:timeout=5, max=97
Server:Apache/2.4.10 (Debian)
Ok in this case all works. But then in the other page, i make the same ajax call and im getting this:
Request URL:http://192.168.99.100:3001/seccion
Request Method:POST
Status Code:405 Method Not Allowed
Remote Address:192.168.99.100:3001
Referrer Policy:no-referrer-when-downgrade
And the response header of the call that fails:
allow:POST
Cache-Control:no-cache, private
Connection:close
Content-Type:text/html; charset=UTF-8
Date:Mon, 07 Aug 2017 19:26:57 GMT
Server:Apache/2.4.10 (Debian)
X-Powered-By:PHP/7.1.7
We can see POST is allowed in the response header but im getting this "Code:405 Method Not Allowed"
I dont know what is happing, any clue?
Thanks.
The problem was that i put "{{ method_field('PATCH') }}" in the form that wraps the select dropdown that fires the ajax call, so a _method parameter with "PATCH" value is passed in the data of the ajax call and throws the "methodNotAllowed" error.
I fixed it just passing the data i need and not all the form serialized:
$.ajax({
type: "post",
url: "{{ route("filtro.secciones") }}",
data: $("#form").find('#zonas').serialize(),//<-- solution
dataType: "json",
success: function (datos) {
//my code
},
error: function (request, status, error) {
console.log(error);
}
});
I am using ExtJs to create a button that do an ajax post to my django application, but the post is blocked by a FORBIDDEN (403) error.
I tryed to pass the CSRF token in as POST data by setting a custom X-CSRFToken header to the value of the CSRF token (https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax) without success
ExtJS.js
action = new Ext.Button({
text: 'Ajax Test',
handler: function () {
Ext.Ajax.request({
url: 'test/',
method: 'POST',
headers: { 'Content-Type': 'application/json'},
params: {'test': 'test'},
success: function(response, opts) {
var obj = Ext.decode(response.responseText);
console.dir(obj);
},
failure: function(response, opts) {
console.log('server-side failure');
}
});
},
});
view.py
def test(request):
print "TEST WORKING"
print dict(request.POST.copy().iteritems())
return HttpResponse("")
CHROME NETWORK TAB:
Response:
CSRF verification failed. Request aborted.
Cookies:
Request Cookies:
csrftoken : S7uLgmhqeprWqL4NdH9mznIfpTgyM9RP
djdt : hide
djdttop : 30
sessionid : sx4ukmkitqp39wvuve1a9zed2kjiwfb1
Response Cookies:
(empty)
Headers:
Request URL:http://127.0.0.1:8000/basqui/layer/edit/2/test/
Request Method:POST
Status Code:403 FORBIDDEN
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:9
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:sessionid=sx4ukmkitqp39wvuve1a9zed2kjiwfb1; csrftoken=S7uLgmhqeprWqL4NdH9mznIfpTgyM9RP; djdttop=30; djdt=hide
Host:127.0.0.1:8000
Origin:http://127.0.0.1:8000
Referer:http://127.0.0.1:8000/basqui/layer/edit/2
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
Form Dataview sourceview URL encoded
test:test
Response Headersview source
Content-Type:text/html
Date:Tue, 07 Jan 2014 16:52:15 GMT
Server:WSGIServer/0.1 Python/2.7.5
X-Frame-Options:SAMEORIGIN
action = new Ext.Button({
text: 'Ajax Test',
handler: function () {
var csrf = Ext.util.Cookies.get('csrftoken');
Ext.Ajax.request({
url: 'test/',
method: 'POST',
headers: { 'Content-Type': 'application/json'},
params: {'test': 'test', 'csrfmiddlewaretoken': csrf},
success: function(response, opts) {
var obj = Ext.decode(response.responseText);
console.dir(obj);
},
failure: function(response, opts) {
console.log('server-side failure');
}
});
},
});
https://www.sencha.com/forum/showthread.php?134125-Django-1-3-Login-with-ExtJS-4-and-CSRF
I put this in my Application launch function:
Ext.require(["Ext.util.Cookies", "Ext.Ajax"], function(){
// Add csrf token to every ajax request
var token = Ext.util.Cookies.get('csrftoken');
if(!token){
Ext.Error.raise("Missing csrftoken cookie");
} else {
Ext.Ajax.defaultHeaders = Ext.apply(Ext.Ajax.defaultHeaders || {}, {
'X-CSRFToken': token
});
}
});
I have a page locations.aspx that has a method behind it in locations.aspx/getData. when I use the code
$http.jsonp($scope.url)
.success(function (data, status, headers, config) {
alert(data);
}).error(function (data, status, headers, config) {
$scope.status = status;
});
with the $scope.url being locations.aspx/getData it loads the html page of the aspx page but doesn't access the method. I can access the method using
$.ajax({
type: "POST",
url: $scope.url,
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (p) {
var temp = $.parseJSON(p.d);
$scope.allItems.push(temp);
},
error: function () {
alert('error');
}
});
but the data never updates or binds on the view side. An example on the html is
<select ng-model="selectLocation" id="selectLocation" ng-change="onLocationChange()">
<option></option>
<option ng-repeat="l in allItems">{{l.location}}</option>
</select>
After the ajax call allItems array does have an item in it but the view never updates.
My ajax call headers are
Request URL:localhost:41796/locations.aspx/getData
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:application/json, text/javascript, /; q=0.01
Content-Type:application/json; charset=utf-8
Response Headersview source
Cache-Control:private, max-age=0
Connection:Close
Content-Length:270
Content-Type:application/json; charset=utf-8
and my $http headers are
Request URL:localhost:41796/locations.aspx/getData
Request Method:GET
Status Code:200 OK
Request Headersview parsed
GET /locations.aspx/getData HTTP/1.1
Host: localhost:41796
Connection: keep-alive
Response Headersview parsed
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 7177
Connection: Close
Based on the discussion above, it seems you're using ASP.NET and running into specific issues with it.
ASP.NET can be pretty picky sometimes about what it will parse and what it won't -- especially when it comes to MVC (which it doesn't appear that you're using here, but perhaps [WebMethod] (what I assume you're using) has the same kinds of issues).
Instead of messing with jQuery's $.ajax, you can use Angular's $http in the same way:
$http({
method: 'POST',
url: $scope.url,
contentType: 'application/json; charset=utf-8'
})
.success(function (data, status, headers, config) {
alert(data);
})
.error(function (data, status, headers, config) {
$scope.status = status;
});
Check this: http://docs.angularjs.org/api/ng.$http#Parameters for more information.
I am trying to perform an AJAX request to a Play application on Heroku from my local machine. Currently, the 'complete' and 'error' handlers are being invoke but not the 'success'. In Opera and Firefox, my response headers are:
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Server: Play! Framework;1.2.4;prod
Set-Cookie: PLAY_FLASH=;Expires=Fri, 5-Oct-12 08:22:46 GMT;Path=/
Set-Cookie: PLAY_ERRORS=;Expires=Fri, 5-Oct-12 08:22:46 GMT;Path=/
Set-Cookie: PLAY_SESSION=;Expires=Fri, 5-Oct-12 08:22:46 GMT;Path=/
Content-Length: 2295
Connection: keep-alive
Opera also shows the returned JSON object
Here is my code:
var url = "http://myurl.com"
$.ajax({
'complete': function (jqXHR, status) {
console.log('Complete!');
console.log(status);
console.log(jqXHR.getAllResponseHeaders());
},
'dataType': "application/json",
'error': function (jqXHR, status, error) {
console.log('Error!');
console.log(status);
console.log(error);
},
'success': function (data, status, jqXHR) {
console.log('Success!');
console.log(status);
console.log(data);
},
'type': 'GET',
'url': url
});
Other similar questions suggested changing the datatype to text or removing it altogether: neither work. I have successfully validated the returned JSON object at JSONLint.
The console log is:
Error!
error
Complete!
error
I'm not sure if it is linked, but the getAllResponseHeaders() function is returning an empty string.
Is this a cross domain error?
Any help is welcome!
Thanks
Here they suggest that it is indeed a cross domain error.