jQuery 如何让跨域资源共享 (CORS) 发布请求工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5750696/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 19:45:44  来源:igfitidea点击:

How to get a cross-origin resource sharing (CORS) post request working

jqueryajaxcherrypycors

提问by James

I have a machine on my local lan (machineA) that has two web servers. The first is the in-built one in XBMC (on port 8080) and displays our library. The second server is a CherryPy python script (port 8081) that I am using to trigger a file conversion on demand. The file conversion is triggered by a AJAX POST request from the page served from the XBMC server.

我的本地局域网 (machineA) 上有一台机器,它有两个 Web 服务器。第一个是 XBMC 中的内置(在端口 8080)并显示我们的库。第二个服务器是一个 CherryPy python 脚本(端口 8081),我用它来按需触发文件转换。文件转换由来自 XBMC 服务器提供的页面的 AJAX POST 请求触发。

  • Goto http://machineA:8080which displays library
  • Library is displayed
  • User clicks on 'convert' link which issues the following command -
  • 转到显示库的http://machineA:8080
  • 显示库
  • 用户单击发出以下命令的“转换”链接 -

jQuery Ajax Request

jQuery Ajax 请求

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • The browser issues a HTTP OPTIONS request with the following headers;
  • 浏览器发出带有以下标头的 HTTP OPTIONS 请求;

Request Header - OPTIONS

请求标头 - 选项

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://machineA:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-requested-with
  • The server responds with the following;
  • 服务器响应如下;

Response Header - OPTIONS (STATUS = 200 OK)

响应头 - 选项(状态 = 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:40:29 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1
  • The conversation then stops. The browser, should in theory, issue a POST request as the server responded with the correct (?) CORS headers (Access-Control-Allow-Origin: *)
  • 谈话随即停止。理论上,当服务器使用正确的 (?) CORS 标头(Access-Control-Allow-Origin:*)响应时,浏览器应该发出 POST 请求

For troubleshooting, I have also issued the same $.post command from http://jquery.com. This is where I am stumped, from jquery.com, the post request works, a OPTIONS request is sent following by a POST. The headers from this transaction are below;

为了排除故障,我还从http://jquery.com发出了相同的 $.post 命令。这是我被难住的地方,来自 jquery.com,post 请求有效,一个 OPTIONS 请求在 POST 之后发送。此交易的标题如下;

Request Header - OPTIONS

请求标头 - 选项

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://jquery.com
Access-Control-Request-Method: POST

Response Header - OPTIONS (STATUS = 200 OK)

响应头 - 选项(状态 = 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1

Request Header - POST

请求头 - POST

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://jquery.com/
Content-Length: 12
Origin: http://jquery.com
Pragma: no-cache
Cache-Control: no-cache

Response Header - POST (STATUS = 200 OK)

响应头 - POST (STATUS = 200 OK)

Content-Length: 32
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: application/json

I can't work out why the same request would work from one site, but not the other. I am hoping someone might be able to point out what I am missing. Thanks for your help!

我无法弄清楚为什么相同的请求会在一个站点上起作用,而在另一个站点上不起作用。我希望有人能够指出我所缺少的。谢谢你的帮助!

采纳答案by James

I finally stumbled upon this link "A CORS POST request works from plain javascript, but why not with jQuery?" that notes that jQuery 1.5.1 adds the

我终于偶然发现了这个链接“一个 CORS POST 请求可以通过普通的 javascript 工作,但为什么不使用 jQuery?”,它指出 jQuery 1.5.1 添加了

 Access-Control-Request-Headers: x-requested-with

header to all CORS requests. jQuery 1.5.2 does not do this. Also, according to the same question, setting a server response header of

所有 CORS 请求的标头。jQuery 1.5.2 没有这样做。另外,根据相同的问题,设置服务器响应头

Access-Control-Allow-Headers: *

does not allow the response to continue. You need to ensure the response header specifically includes the required headers. ie:

不允许响应继续。您需要确保响应标头明确包含所需的标头。IE:

Access-Control-Allow-Headers: x-requested-with 

回答by Hassan Zaheer

REQUEST:

要求:

 $.ajax({
            url: "http://localhost:8079/students/add/",
            type: "POST",
            crossDomain: true,
            data: JSON.stringify(somejson),
            dataType: "json",
            success: function (response) {
                var resp = JSON.parse(response)
                alert(resp.status);
            },
            error: function (xhr, status) {
                alert("error");
            }
        });

RESPONSE:

回复:

response = HttpResponse(json.dumps('{"status" : "success"}'))
response.__setitem__("Content-type", "application/json")
response.__setitem__("Access-Control-Allow-Origin", "*")

return response

回答by Dekel

Took me some time to find the solution.

我花了一些时间来找到解决方案。

In case your server response correctly and the request is the problem, you should add withCredentials: trueto the xhrFieldsin the request:

在正常情况下,您的服务器响应和请求的问题,您应该添加withCredentials: truexhrFields在请求:

$.ajax({
    url: url,
    type: method,
    // This is the important part
    xhrFields: {
        withCredentials: true
    },
    // This is the important part
    data: data,
    success: function (response) {
        // handle the response
    },
    error: function (xhr, status) {
        // handle errors
    }
});

Note: jQuery >= 1.5.1 is required

注:jQuery的> = 1.5.1被需要

回答by Miracool

I solved my own problem when using google distance matrix API by setting my request header with Jquery ajax. take a look below.

通过使用 Jquery ajax 设置我的请求标头,我在使用谷歌距离矩阵 API 时解决了我自己的问题。看看下面。

var settings = {
          'cache': false,
          'dataType': "jsonp",
          "async": true,
          "crossDomain": true,
          "url": "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=place_id:"+me.originPlaceId+"&destinations=place_id:"+me.destinationPlaceId+"&region=ng&units=metric&key=mykey",
          "method": "GET",
          "headers": {
              "accept": "application/json",
              "Access-Control-Allow-Origin":"*"
          }
      }

      $.ajax(settings).done(function (response) {
          console.log(response);

      });

Note what i added at the settings
**

请注意我在设置中添加的内容
**

"headers": {
          "accept": "application/json",
          "Access-Control-Allow-Origin":"*"
      }

**
I hope this helps.

**
我希望这会有所帮助。

回答by Pritam Roy

Well I struggled with this issue for a couple of weeks.

好吧,我在这个问题上挣扎了几个星期。

The easiest, most compliant and non hacky way to do this is to probably use a provider JavaScript API which does not make browser based calls and can handle Cross Origin requests.

最简单、最合规和非 hacky 的方法可能是使用提供者 JavaScript API,它不进行基于浏览器的调用并且可以处理跨源请求。

E.g. Facebook JavaScript API and Google JS API.

例如 Facebook JavaScript API 和 Google JS API。

In case your API provider is not current and does not support Cross Origin Resource Origin '*' header in its response and does not have a JS api (Yes I am talking about you Yahoo ),you are struck with one of three options-

如果您的 API 提供者不是最新的,并且在其响应中不支持跨源资源源“*”标头,并且没有 JS api(是的,我说的是雅虎),您会被以下三个选项之一震惊-

  1. Using jsonp in your requests which adds a callback function to your URL where you can handle your response. Caveat this will change the request URL so your API server must be equipped to handle the ?callback= at the end of the URL.

  2. Send the request to your API server which is controller by you and is either in the same domain as the client or has Cross Origin Resource Sharing enabled from where you can proxy the request to the 3rd party API server.

  3. Probably most useful in cases where you are making OAuth requests and need to handle user interaction Haha! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

  1. 在您的请求中使用 jsonp 将回调函数添加到您的 URL,您可以在其中处理您的响应。请注意,这会更改请求 URL,因此您的 API 服务器必须能够处理 URL 末尾的 ?callback=。

  2. 将请求发送到您的 API 服务器,该服务器是您的控制器,并且与客户端位于同一域中,或者启用了跨源资源共享,您可以从中将请求代理到第 3 方 API 服务器。

  3. 在您发出 OAuth 请求并需要处理用户交互的情况下可能最有用哈哈! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

回答by M K

Using this in combination with Laravel solved my problem. Just add this header to your jquery request Access-Control-Request-Headers: x-requested-withand make sure that your server side response has this header set Access-Control-Allow-Headers: *.

将此与 Laravel 结合使用解决了我的问题。只需将此标头添加到您的 jquery 请求中Access-Control-Request-Headers: x-requested-with,并确保您的服务器端响应设置了此标头Access-Control-Allow-Headers: *

回答by lepe

This is a summary of what worked for me:

这是对我有用的总结:

Define a new function (wrapped $.ajaxto simplify):

定义一个新函数(包装$.ajax以简化):

jQuery.postCORS = function(url, data, func) {
  if(func == undefined) func = function(){};
  return $.ajax({
    type: 'POST', 
    url: url, 
    data: data, 
    dataType: 'json', 
    contentType: 'application/x-www-form-urlencoded', 
    xhrFields: { withCredentials: true }, 
    success: function(res) { func(res) }, 
    error: function() { 
            func({}) 
    }
  });
}

Usage:

用法:

$.postCORS("https://example.com/service.json",{ x : 1 },function(obj){
      if(obj.ok) {
           ...
      }
});

Also works with .done,.fail,etc:

也有工作.done.fail等:

$.postCORS("https://example.com/service.json",{ x : 1 }).done(function(obj){
      if(obj.ok) {
           ...
      }
}).fail(function(){
    alert("Error!");
});

Server side (in this case where example.com is hosted), set these headers (added some sample code in PHP):

服务器端(在本例中托管 example.com),设置这些标头(在 PHP 中添加了一些示例代码):

header('Access-Control-Allow-Origin: https://not-example.com');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 604800');
header("Content-type: application/json");
$array = array("ok" => $_POST["x"]);
echo json_encode($array);

This is the only way I know to truly POST cross-domain from JS.

这是我知道的从 JS 真正跨域 POST 的唯一方法。

JSONP converts the POST into GET which may display sensitive information at server logs.

JSONP 将 POST 转换为 GET,它可能会在服务器日志中显示敏感信息。

回答by Victor Stoddard

For some reason, a question about GET requests was merged with this one, so I'll respond to it here.

由于某种原因,一个关于GET请求的问题与这个问题合并了,所以我会在这里回复。

This simple function will asynchronously get an HTTP status reply from a CORS-enabled page. If you run it, you'll see that only a page with the proper headers returns a 200 status if accessed via XMLHttpRequest -- whether GET or POST is used. Nothing can be done on the client side to get around this except possibly using JSONP if you just need a json object.

这个简单的函数将从启用 CORS 的页面异步获取 HTTP 状态回复。如果运行它,您将看到只有具有正确标题的页面在通过 XMLHttpRequest 访问时才返回 200 状态——无论是使用 GET 还是 POST。如果您只需要一个 json 对象,除了可能使用 JSONP 之外,在客户端无法做任何事情来解决这个问题。

The following can be easily modified to get the data held in the xmlHttpRequestObject object:

可以轻松修改以下内容以获取保存在 xmlHttpRequestObject 对象中的数据:

function checkCorsSource(source) {
  var xmlHttpRequestObject;
  if (window.XMLHttpRequest) {
    xmlHttpRequestObject = new XMLHttpRequest();
    if (xmlHttpRequestObject != null) {
      var sUrl = "";
      if (source == "google") {
        var sUrl = "https://www.google.com";
      } else {
        var sUrl = "https://httpbin.org/get";
      }
      document.getElementById("txt1").innerHTML = "Request Sent...";
      xmlHttpRequestObject.open("GET", sUrl, true);
      xmlHttpRequestObject.onreadystatechange = function() {
        if (xmlHttpRequestObject.readyState == 4 && xmlHttpRequestObject.status == 200) {
          document.getElementById("txt1").innerHTML = "200 Response received!";
        } else {
          document.getElementById("txt1").innerHTML = "200 Response failed!";
        }
      }
      xmlHttpRequestObject.send();
    } else {
      window.alert("Error creating XmlHttpRequest object. Client is not CORS enabled");
    }
  }
}
<html>
<head>
  <title>Check if page is cors</title>
</head>
<body>
  <p>A CORS-enabled source has one of the following HTTP headers:</p>
  <ul>
    <li>Access-Control-Allow-Headers: *</li>
    <li>Access-Control-Allow-Headers: x-requested-with</li>
  </ul>
  <p>Click a button to see if the page allows CORS</p>
  <form name="form1" action="" method="get">
    <input type="button" name="btn1" value="Check Google Page" onClick="checkCorsSource('google')">
    <input type="button" name="btn1" value="Check Cors Page" onClick="checkCorsSource('cors')">
  </form>
  <p id="txt1" />
</body>
</html>

回答by ozzieisaacs

I had the exact same issue where jquery ajax only gave me cors issues on post requests where get requests worked fine - I tired everything above with no results. I had the correct headers in my server etc. Changing over to use XMLHTTPRequest instead of jquery fixed my issue immediately. No matter which version of jquery I used it didn't fix it. Fetch also works without issues if you don't need backward browser compatibility.

我遇到了完全相同的问题,jquery ajax 只给了我关于 post 请求的 cors 问题,其中 get 请求工作正常 - 我厌倦了上面的一切,没有结果。我的服务器等中有正确的标头。改用 XMLHTTPRequest 而不是 jquery 立即解决了我的问题。无论我使用哪个版本的 jquery,它都没有修复它。如果您不需要向后浏览器兼容性,Fetch 也可以正常工作。

        var xhr = new XMLHttpRequest()
        xhr.open('POST', 'https://mywebsite.com', true)
        xhr.withCredentials = true
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 2) {// do something}
        }
        xhr.setRequestHeader('Content-Type', 'application/json')
        xhr.send(json)

Hopefully this helps anyone else with the same issues.

希望这可以帮助其他有同样问题的人。

回答by llange

If for some reasons while trying to add headers or set control policy you're still getting nowhere you may consider using apache ProxyPass…

如果在尝试添加标头或设置控制策略时由于某些原因您仍然无处可去,您可以考虑使用 apache ProxyPass ...

For example in one <VirtualHost>that uses SSL add the two following directives:

例如,在<VirtualHost>使用 SSL 的一个中添加以下两个指令:

SSLProxyEngine On
ProxyPass /oauth https://remote.tld/oauth

Make sure the following apache modules are loaded (load them using a2enmod):

确保加载了以下 apache 模块(使用 a2enmod 加载它们):

  • proxy
  • proxy_connect
  • proxy_http
  • 代理
  • 代理连接
  • proxy_http

Obviously you'll have to change your AJAX requests url in order to use the apache proxy…

显然,您必须更改 AJAX 请求 url 才能使用 apache 代理……