使用 CORS 到 API 网关的 AJAX POST 不起作用,但可以使用 CURL 进行 POST
Posted
技术标签:
【中文标题】使用 CORS 到 API 网关的 AJAX POST 不起作用,但可以使用 CURL 进行 POST【英文标题】:AJAX POST with CORS to API Gateway does not work, although can POST with CURL 【发布时间】:2017-03-19 11:25:34 【问题描述】:所以我尝试使用 $.ajax() 调用将数据提交到 API 端点。我已验证我可以使用curl
命令进行 POST,格式如下:
curl -X POST -H "Content-Type: application/json" -d "\"uname\":\"myusername2\",\"emailAddr\":\"user2@ex.com\"" <url to my API endpoint>
curl
命令返回一个空的 JSON 响应(看起来像 ),我的数据被放入数据库(这是我配置 API Gateway 端点要做的事情)。
但是,当我尝试使用 $.ajax()
命令执行此操作时,该命令被编程为在填写表单数据后触发单击的按钮,但我无法使其工作。
var obj = new Object();
obj.uname = $uname;
obj.emailAddr = $email;
var stringedObj = JSON.stringify(obj);
alert("stringified: " + stringedObj);
$.ajax(
url: '<same url as in curl>',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(obj),
success: function(data)
alert(JSON.stringify(data));
,
error: function(e)
alert("failed" + JSON.stringify(e));
);
每当我运行此程序时,我都可以从第一条警报消息中看到我的数据已正确字符串化。但是,我总是收到如下所示的错误消息:
failed"readyState":0,"responseText":"","status":0,"statusText":"error"
我想知道是否可以获得更详细的错误响应。另外,我尝试过使用parseData: false
和crossdomain: true
。再一次,当我使用 curl 时它可以工作,所以我很确定这不是 API 网关配置问题。
感谢您的所有帮助!
编辑:我从下面关于 javascript 控制台的评论中了解到。现在我发现这是由于未启用 CORS。我在 AWS Api Gateway 中启用了 CORS,等待它完成,然后将我的请求更改为:
$.ajax(
url: '<my url>',
type: 'POST',
data: JSON.stringify(obj),
dataType: 'json',
crossDomain: true,
success: function(data)
alert(JSON.stringify(data));
,
error: function(e)
alert("failed" + JSON.stringify(e));
);
我在 javascript 控制台中得到了关于需要 CORS 的相同响应。 Other threads on CORS have shown 以此为例。我想知道是否需要自定义标头,尽管我尝试添加 headers: "Access-Control-Allow-Origin": "*"
并且仍然从 javascript 控制台得到相同的响应:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://k6i6wk8487.execute-api.us-west-2.amazonaws.com/prod/comments. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
【问题讨论】:
Javascript 控制台有错误吗?比如不允许跨域的错误? 我同意@Barmar - CORS ... @Barmar 感谢您的提示!是的,我发现 CORS 被拒绝,所以我在 API 网关中启用了它。但是,我仍然收到标题 Access-Control-Allow-Origin 丢失的消息。我添加了 crossDomain: true 和 dataType: 'json' set,我从 javascript 控制台收到了相同的错误消息。 *** 上的其他线程说添加这两个选项是所有必要的。我是否需要添加自定义标题,如果需要怎么办?我尝试使用标题:“Access-Control-Allow-Origin”:“*”,但这也没有帮助。再次感谢Access-Control-Allow-Origin: "*"
需要在端点设置,而不是通过您的 Ajax 请求。
Access-Control-Allow-Origin
标头需要在您的 AWS 服务器上配置。虽然@amdouglas 提供了一个选项来指定这一点,但我建议您将该标头锁定到单个必要的域作为额外的安全措施(即Access-Control-Allow-Origin: http://www.example.com
),而不是对所有域进行通配符...跨度>
【参考方案1】:
您可以使用 JSONP 技术发出请求:
<script>
function parseJSONP(response)
// Process the JSON response here.
function loadScript(url, data, callback)
script = document.createElement('script');
document.getElementsByTagName('head')[0].appendChild(script);
script.src = url
+'?callback='+callback
+'&data='+encodeURIComponent(JSON.stringify(data))
;
loadScript('http://yourdifferentdomain', yourdata, 'parseJSONP');
</script>
您可能需要调整远程服务以接受和解码 URL 中的数据参数。
另一种可能更好的方法是将您的外部 URL 作为参数包装,将 POST 数据的一部分发送到您的本地 CURL,让服务器获取其他域的响应,并将其放回来自同一域的响应中。按照你的例子:
JS:
var curlBridge = 'http://samedomain/curl-resource/';
var remoteURL = 'http://otherdomain/target-resource/';
var obj = ; // Your data to cross-domain post.
$.ajax(
url: curlBridge,
type: 'POST',
data: JSON.stringify(
"url": remoteURL,
"headers": null, // Headers you may want to pass
"post": obj
),
dataType: 'json',
crossDomain: true,
contentType: 'application/json',
success: function(data)
alert(JSON.stringify(data));
,
error: function(ev)
alert("failed" + JSON.stringify(ev));
);
php:
<?php
function callUrl($url, $post = null, $headers = null)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 60000); // DEF 1000*60... // Hide/Show
$post_str = "";
if (is_array($post))
if (count($post))
foreach ($post as $key => $val)
if (is_array($val) && count($val)) $val = json_encode($val);
$post_str .= "&".$key."=".$val;
if ($post_str[0] == "&") $post_str = substr($post_str, 1);
else $post_str = "".$post;
if ($post_str || is_array($post))
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_str);
if (is_array($headers) && count($headers))
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
else $headers = array();
$result = curl_exec($ch);
curl_close($ch);
return $result;
$input = array_merge($_GET, $_POST);
echo callUrl($input['url'], $input['post'], $input['headers']);
【讨论】:
感谢您的回复哈维尔。但是,该代码 sn-p 是 GET 请求吗?有没有办法将其转换为 POST?在最后一段中,您的意思是因为 CORS 对服务器构建两个单独的调用吗?我还没有看到任何其他示例执行两个单独的调用,尽管这是有道理的,一个用于 OPTIONS,一个用于 POST。再次感谢。 很遗憾没有。对于跨域发布,我宁愿使用第二种方法。几年前我在 PHP 中做过。它是本地客户端和远程资源之间基于 CURL 的桥梁。添加到答案中的简短示例。【参考方案2】:想通了,在将 AWS API Gateway 更新为启用 CORS 后,我没有在 AWS API Gateway 中点击“部署”。嗬!感谢所有帮助过的人。这是我最后的 ajax 调用:
$.ajax(
url: $invokeUrl,
type: 'POST',
data: JSON.stringify(obj),
dataType: 'json',
crossDomain: true,
contentType: 'application/json',
success: function(data)
alert(JSON.stringify(data));
,
error: function(e)
alert("failed" + JSON.stringify(e));
感谢所有提供帮助的人,如果您在使用 API Gateway 时遇到此问题,请告诉我,我会尽力提供帮助。
【讨论】:
其实,你的Doh!评论对我帮助最大.. 因为在首先创建资源时,您可以选择启用 CORS。因此,当您这样做时,您没有意识到您仍然必须通过操作启用 CORS(..然后重新部署..)。谢谢。以上是关于使用 CORS 到 API 网关的 AJAX POST 不起作用,但可以使用 CURL 进行 POST的主要内容,如果未能解决你的问题,请参考以下文章
从 Ajax 调用 Spring Boot Rest API 时出现 CORS 错误
使用 AWS CDK 为 AWS API 网关启用 CORS
使用代理集成时,API 网关和 Lambda 出现 CORS 错误**仅**
将表单从客户端发布到 AWS API 网关功能时如何修复 CORS 错误?
放大:即使在 API 网关和 Lambda 标头中启用了 CORS,但 CORS 标头“Access-Control-Allow-Origin”缺失错误