如何通过 JavaScript 发送跨域 POST 请求?

2022-08-29 22:41:51

如何通过 JavaScript 发送跨域 POST 请求?

注意 - 它不应该刷新页面,之后我需要抓取并解析响应。


答案 1

更新:在继续之前,每个人都应该阅读并理解CORS上的html5rocks教程。它很容易理解,非常清楚。

如果您控制要POSTed的服务器,只需通过在服务器上设置响应标头来利用“跨域资源共享标准”。这个答案在这个线程的其他答案中讨论过,但在我看来不是很清楚。

简而言之,这是您如何完成从 from.com/1.html 到 to.com/postHere.php 的跨域POST(以PHP为例)。注意:您只需要为NON请求设置 - 此示例始终为较小的代码片段设置所有标头。Access-Control-Allow-OriginOPTIONS

  1. 在 postHere 中.php设置以下内容:

    switch ($_SERVER['HTTP_ORIGIN']) {
        case 'http://from.com': case 'https://from.com':
        header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
        header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
        header('Access-Control-Max-Age: 1000');
        header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
        break;
    }
    

    这允许您的脚本进行跨域 POST、GET 和 OPTIONS。随着您继续阅读,这将变得清晰...

  2. 从JS设置跨域POST(jQuery示例):

    $.ajax({
        type: 'POST',
        url: 'https://to.com/postHere.php',
        crossDomain: true,
        data: '{"some":"json"}',
        dataType: 'json',
        success: function(responseData, textStatus, jqXHR) {
            var value = responseData.someKey;
        },
        error: function (responseData, textStatus, errorThrown) {
            alert('POST failed.');
        }
    });
    

当您在步骤2中执行POST时,您的浏览器将向服务器发送“OPTIONS”方法。这是浏览器的“嗅探”,以查看服务器是否很酷,您可以POST它。服务器以“访问控制-允许-源”进行响应,告诉浏览器可以开机自检|获取|如果请求源自“http://from.com”或“https://from.com”,则为 ORIGIN。由于服务器可以接受它,浏览器将发出第二个请求(这次是POST)。最好让客户端设置它要发送的内容类型 - 因此您也需要允许这样做。

MDN有一篇关于HTTP访问控制的精彩文章,详细介绍了整个流程的工作原理。根据他们的文档,它应该“在支持跨站点XMLHttpRequest的浏览器中工作”。然而,这有点误导,因为我认为只有现代浏览器才允许跨域POST。我只验证了这适用于野生动物园,铬,FF 3.6。

如果执行此操作,请记住以下几点:

  1. 您的服务器必须处理每个操作 2 个请求
  2. 您将不得不考虑安全隐患。在执行类似“访问控制-允许-源:*”之类的操作之前要小心
  3. 这在移动浏览器上不起作用。根据我的经验,他们根本不允许跨域POST。我测试过安卓,iPad,iPhone
  4. FF < 3.6 中有一个非常大的错误,如果服务器返回非 400 响应代码并且存在响应正文(例如验证错误),则 FF 3.6 不会获取响应正文。这是一个巨大的痛苦,因为你不能使用良好的REST实践。请参阅此处的错误(它在jQuery下提交,但我的猜测是它是FF错误 - 似乎在FF4中已修复)。
  5. 始终返回上述标头,而不仅仅是在 OPTION 请求上。FF 在 POST 的响应中需要它。

答案 2

如果控制远程服务器,则可能应使用 CORS,如本答案中所述。它在IE8及更高版本中受支持,以及FF,GC和Safari的所有最新版本。(但在 IE8 和 9 中,CORS 不允许你在请求中发送 Cookie。

因此,如果您控制远程服务器,或者您必须支持IE7,或者如果您需要cookie并且必须支持IE8 / 9,则可能需要使用iframe技术。

  1. 创建具有唯一名称的 iframe。(iframes 为整个浏览器使用全局命名空间,因此请选择一个其他网站都不会使用的名称。
  2. 构建一个包含隐藏输入的表单,以 iframe 为目标。
  3. 提交表单。

这是示例代码;我在IE6,IE7,IE8,IE9,FF4,GC11,S5上进行了测试。

function crossDomainPost() {
  // Add the iframe with a unique name
  var iframe = document.createElement("iframe");
  var uniqueString = "CHANGE_THIS_TO_SOME_UNIQUE_STRING";
  document.body.appendChild(iframe);
  iframe.style.display = "none";
  iframe.contentWindow.name = uniqueString;

  // construct a form with hidden inputs, targeting the iframe
  var form = document.createElement("form");
  form.target = uniqueString;
  form.action = "http://INSERT_YOUR_URL_HERE";
  form.method = "POST";

  // repeat for each parameter
  var input = document.createElement("input");
  input.type = "hidden";
  input.name = "INSERT_YOUR_PARAMETER_NAME_HERE";
  input.value = "INSERT_YOUR_PARAMETER_VALUE_HERE";
  form.appendChild(input);

  document.body.appendChild(form);
  form.submit();
}

小心!您将无法直接读取 POST 的响应,因为 iframe 存在于单独的域中。不允许框架从不同的域相互通信;这是同源策略

如果您控制远程服务器但无法使用 CORS(例如,因为您使用的是 IE8/IE9,并且需要使用 Cookie),则有一些方法可以解决同源策略,例如使用 window.postMessage 和/或允许您在较旧的浏览器中发送跨域跨框架消息的众多库之一:

如果不控制远程服务器,则无法读取 POST 的响应,句点。否则会导致安全问题。