跨域资源共享(CORS)的POST请求可以在纯JavaScript中工作,但为什么不能在jQuery中工作?

251
我在本地局域网上有一台机器(机器A),上面有两个Web服务器。第一个是XBMC内置的服务器(端口8080),用于显示我们的库。第二个服务器是一个CherryPy的Python脚本(端口8081),我用它来按需触发文件转换。文件转换是通过从XBMC服务器提供的页面发出的AJAX POST请求来触发的。
  • 访问http://machineA:8080,显示库
  • 库被显示出来
  • 用户点击“转换”链接,发出以下命令 -

jQuery Ajax请求

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})

浏览器发送一个带有以下头部的HTTP OPTIONS请求; 请求头部 - 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

服务器的回应如下; 响应头 - OPTIONS (状态 = 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
  • 对话随之停止。浏览器理论上应该发送一个POST请求,因为服务器响应了正确的CORS标头(Access-Control-Allow-Origin: *)

为了进行故障排除,我还从http://jquery.com发出了相同的$.post命令。这就是我困惑的地方,从jquery.com发送的POST请求有效,然后发送OPTIONS请求,然后再发送POST请求。此事务的标头如下;

请求头 - 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

响应头 - OPTIONS(状态 = 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

请求头 - 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

响应头 - POST(状态 = 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

我弄不清楚为什么同样的请求在一个网站上可以工作,但在另一个网站上却不行。希望有人能指出我漏掉了什么。谢谢你的帮助!

如果两个Web服务器在同一台机器上,是否需要CORS? - jdigital
11
据我所知,由于不同的端口,它是一个CORS请求。另外,OPTIONS请求表明浏览器将其视为CORS请求。 - James
11个回答

-3

虽然我来得有点晚,但我已经苦恼了几天。虽然这是可能的,但我在这里找到的所有答案都没有起作用。 它看起来很简单。 这是 .ajax 调用:

    <!DOCTYPE HTML>
    <html>
    <head>
    <body>
     <title>Javascript Test</title>
     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
     <script type="text/javascript">
     $(document).domain = 'XXX.com';
     $(document).ready(function () {
     $.ajax({
        xhrFields: {cors: false},
        type: "GET",
        url: "http://XXXX.com/test.php?email='steve@XXX.com'",
        success: function (data) {
           alert(data);
        },
        error: function (x, y, z) {
           alert(x.responseText + " :EEE: " + x.status);
        }
    });
    });
    </script> 
    </body>
    </html>

以下是服务器端的 PHP 代码:

    <html>
    <head>
     <title>PHP Test</title>
     </head>
    <body>
      <?php
      header('Origin: xxx.com');
      header('Access-Control-Allow-Origin:*');
      $servername = "sqlxxx";
      $username = "xxxx";
      $password = "sss";
      $conn = new mysqli($servername, $username, $password);
      if ($conn->connect_error) {
        die( "Connection failed: " . $conn->connect_error);
      }
      $sql = "SELECT email, status, userdata  FROM msi.usersLive";
      $result = $conn->query($sql);
      if ($result->num_rows > 0) {
      while($row = $result->fetch_assoc()) {
        echo $row["email"] . ":" . $row["status"] . ":" . $row["userdata"] .  "<br>";
      }
    } else {
      echo "{ }";
    }
    $conn->close();
    ?>
    </body>


1
就此而言,Origin标头是一个请求标头,而不是响应标头。您的php脚本不应该设置它。 - Noodles
哼。这让我很失望,因为我看到你在代码中使用了 AJAX 的“GET”,而 OP 明确表示他想避免使用“GET”并想使用“POST”。 - Steve Sauder
CORS头部在涉及的动词方面工作方式相同。只要服务器配置正确,我们就能通过$.ajax()调用所有动词。最难的部分是正确获取“Access-Control-Request-Headers”,但即使如此也不太困难。正如之前的帖子所指出的那样,这不能是通配符,而必须是标头的白名单。 - escape-llc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接