使用 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: falsecrossdomain: 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 错误

API 网关 CORS 问题

使用 AWS CDK 为 AWS API 网关启用 CORS

使用代理集成时,API 网关和 Lambda 出现 CORS 错误**仅**

将表单从客户端发布到 AWS API 网关功能时如何修复 CORS 错误?

放大:即使在 API 网关和 Lambda 标头中启用了 CORS,但 CORS 标头“Access-Control-Allow-Origin”缺失错误