CORS (Cross-Origin Resource Sharing) 사후 요청 작업 방법


216

두 개의 웹 서버가있는 로컬 LAN (machineA)에 컴퓨터가 있습니다. 첫 번째는 XBMC (포트 8080)에 내장 된 것으로 라이브러리를 표시합니다. 두 번째 서버는 필요할 때 파일 변환을 트리거하는 데 사용하는 CherryPy 파이썬 스크립트 (포트 8081)입니다. 파일 변환은 XBMC 서버에서 제공 한 페이지의 AJAX POST 요청에 의해 트리거됩니다.

  • 고토 에 http : // machineA : 8080 있는 표시 라이브러리
  • 라이브러리가 표시됩니다
  • 사용자가 다음 명령을 실행하는 '변환'링크를 클릭하십시오.

jQuery Ajax 요청

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • 브라우저는 다음 헤더와 함께 HTTP 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
  • 서버는 다음과 같이 응답합니다.

응답 헤더-옵션 (상태 = 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
  • 대화가 중지됩니다. 이론적으로 브라우저는 서버가 올바른 (?) CORS 헤더 (Access-Control-Allow-Origin : *)로 응답 할 때 POST 요청을 발행해야합니다.

문제 해결을 위해 http://jquery.com 에서 동일한 $ .post 명령도 발행했습니다 . jquery.com에서 게시 요청이 작동하고 OPTIONS 요청이 POST에 의해 전송되는 곳입니다. 이 거래의 헤더는 다음과 같습니다.

요청 헤더-옵션

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

응답 헤더-옵션 (상태 = 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 (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

한 사이트에서 동일한 요청이 작동하지만 다른 사이트에서는 작동하지 않는 이유를 해결할 수 없습니다. 누군가 내가 누락 된 것을 지적 할 수 있기를 바랍니다. 당신의 도움을 주셔서 감사합니다!


두 웹 서버가 동일한 시스템에있는 경우 CORS가 필요합니까?
jdigital

8
내가 아는 한 다른 포트 때문에 CORS 요청입니다. 또한 OPTIONS 요청은 브라우저가이를 CORS 요청으로 취급하고 있음을 나타냅니다
James

답변:


157

마지막으로이 링크를 우연히 발견했습니다. " CORS POST 요청은 일반 자바 스크립트에서 작동하지만 왜 jQuery에서는 작동하지 않습니까? "

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

모든 CORS 요청에 대한 헤더. jQuery 1.5.2는 이것을하지 않습니다. 또한 같은 질문에 따라 서버 응답 헤더를

Access-Control-Allow-Headers: *

응답을 계속할 수 없습니다. 응답 헤더에 필요한 헤더가 포함되어 있는지 확인해야합니다. 즉 :

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

70

의뢰:

 $.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 = HttpResponse(json.dumps('{"status" : "success"}'))
response.__setitem__("Content-type", "application/json")
response.__setitem__("Access-Control-Allow-Origin", "*")

return response

3
서버가 교차 출처를 허용하지 않으면 crossdomain = true로 문제를 해결할 필요가 없습니다. dataType : "jsonp"를 사용하고 jsonpCallback : "response"와 같은 콜백을 설정하는 것이 더 좋습니다. 또한보십시오 : api.jquery.com/jquery.ajax
BonifatiusK

14

Jquery ajax로 요청 헤더를 설정하여 Google 거리 매트릭스 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);

      });

설정에서 추가 한 내용을 확인하십시오.
**

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

**
이것이 도움이 되었기를 바랍니다.


이것은 서버 측에서 아무것도 변경하지 않고 우리를 위해 일한 유일한 솔루션입니다 ... thanx miracool
Timsta

1
@ Timsta, 내 제안이 당신을 위해 일한 것을 기쁘게 생각합니다. 오버플로도 감사합니다. 좋은 하루 보내세요
Miracool

13

해결책을 찾기 위해 시간을 보냈습니다.

경우 서버 올바르게 응답 및 요청은 문제가, 당신은 추가해야합니다입니다 withCredentials: true받는 xhrFields요청에 :

$.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
    }
});

참고 : jQuery> = 1.5.1이 필요합니다


jquery 버전 확인? 설정 withCredentials: true했습니까? 관련 헤더가 있습니까?
Dekel

예, 1withCredential : true , jquery 버전 : 3.2.1입니다. 실제로 그것은 우편 배달부를 통해 일하고 있지만 크롬 브라우저를 통과하지 못합니다
Mox Shah

1
나는 postman이 브라우저가 아니고 행동이 다르기 때문에 CORS 문제가 없어야한다고 확신합니다. 서버에서 클라이언트로 올바른 관련 헤더를 보내시겠습니까? 다시 한번 말하지만이 변경으로 충분 하지 않습니다. 서버가 올바른 헤더로 응답해야합니다 .
Dekel

서버에 필요한 응답 헤더는 무엇입니까?
Mox Shah

@ MoxShah 이것은 완전히 다른 질문이며 거기에 많은 자료가 있습니다 :)
Dekel

9

글쎄, 나는 몇 주 동안이 문제로 어려움을 겪었습니다.

이 작업을 수행하는 가장 쉽고 가장 적합하고 해킹이없는 방법은 브라우저 기반 호출을하지 않고 Cross Origin 요청을 처리 할 수있는 공급자 JavaScript API를 사용하는 것입니다.

예 : Facebook JavaScript API 및 Google JS API

API 제공자가 최신 상태가 아니며 응답에서 Cross Origin Resource Origin '*'헤더를 지원하지 않고 JS API가없는 경우 (예, Yahoo에 대해 이야기하고 있습니다), 다음 세 가지 옵션 중 하나에 해당합니다.

  1. 요청에 jsonp를 사용하면 응답을 처리 할 수있는 URL에 콜백 함수가 추가됩니다. 주의하면 요청 URL이 변경되므로 API 서버는 URL 끝에? callback =을 처리 할 수 ​​있어야합니다.

  2. 귀하가 컨트롤러 인 API 서버에 요청을 보내고 클라이언트와 동일한 도메인에 있거나 타사 API 서버에 요청을 프록시 할 수있는 Cross Origin Resource Sharing을 사용하도록 설정하십시오.

  3. OAuth 요청을하고 사용자 상호 작용을 처리해야하는 경우에 가장 유용 할 것입니다. window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')


4

이것을 Laravel과 함께 사용하면 문제가 해결되었습니다. 이 헤더를 jquery 요청에 추가 Access-Control-Request-Headers: x-requested-with하고 서버 측 응답에이 헤더가 설정되어 있는지 확인하십시오 Access-Control-Allow-Headers: *.


6
CORS 헤더를 요청에 수동으로 추가 할 이유가 없습니다. 브라우저는 항상 소품 CORS 헤더를 요청에 추가합니다.
Ray Nicholus

1
실제 문제는 서버가 올바른 Access-Control-Allow-HeadersJQ를 제공하고 Access-Control-Request-Headers(및 코드를 통해 추가 한 모든 것) 와일드 카드가 아닌 서버에 응답하도록하는 것입니다. If-None-Match서버에 목록이없는 경우 , 예를 들어 조건부 GET을 사용하여 프리 플라이트를 날리는 데에는 하나의 "나쁜"헤더 만 필요 합니다.
escape-llc

1

어떤 이유로 GET 요청에 대한 질문이이 요청과 병합되었으므로 여기에 응답하겠습니다.

이 간단한 함수는 CORS 가능 페이지에서 비동기 적으로 HTTP 상태 응답을받습니다. XMLHttpRequest를 통해 액세스하면 GET 또는 POST 사용 여부에 관계없이 적절한 헤더가있는 페이지 만 200 상태를 반환한다는 것을 알 수 있습니다. json 객체가 필요한 경우 JSONP를 사용하는 경우를 제외하고는 클라이언트 측에서 아무것도 해결할 수 없습니다.

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>


1

jquery ajax가 요청을 올바르게 처리 한 게시물 요청에 대해서만 cors 문제를 낸 것과 동일한 문제가 발생했습니다. 결과없이 위의 모든 것을 피곤하게했습니다. 내 서버 등에 올바른 헤더가 있습니다. jquery 대신 XMLHTTPRequest를 사용하도록 변경하면 즉시 문제가 해결되었습니다. 어떤 버전의 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)

잘하면 이것은 같은 문제를 가진 다른 사람들을 도울 것입니다.


1

이것은 나를 위해 일한 것에 대한 요약입니다.

새 기능을 정의하십시오 ( $.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({}) 
    }
  });
}

용법:

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

또한 작동 .done, .fail등 :

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

서버 측 (이 경우 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);

이것이 JS에서 크로스 도메인을 실제로 POST하는 것을 아는 유일한 방법입니다.

JSONP는 POST를 GET으로 변환하여 서버 로그에 중요한 정보를 표시 할 수 있습니다.


0

헤더를 추가하거나 제어 정책을 설정하는 동안 어떤 이유로 든 여전히 아파치 ProxyPass를 사용하는 것을 고려할 수 없습니다 ...

예를 들어 <VirtualHost>SSL을 사용하는 경우 다음 두 지시문을 추가하십시오.

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

다음 아파치 모듈이로드되었는지 확인하십시오 (a2enmod를 사용하여로드).

  • 대리
  • proxy_connect
  • proxy_http

아파치 프록시를 사용하려면 AJAX 요청 URL을 변경해야합니다.


-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 스크립트가 설정해서는 안됩니다.
국수

흠. 이것은 내 희망을 얻은 다음 코드에서 AJAX "GET"을 작성하는 것을 보았을 때 OP가 "GET"을 사용하여 AVOID를 시도하고 "POST"를 사용하고 싶다고 분명히 말했을 때 대시되었습니다.
Steve Sauder

CORS 헤더는 관련된 동사에 관계없이 동일하게 작동합니다. $.ajax()올바르게 구성된 서버에 대해 모든 동사를 호출 할 수 있습니다. 가장 어려운 부분은 Access-Control-Request-Headers올바른 것이지만 너무 어렵지는 않습니다. 이전 포스터에서 언급했듯이 이것은 와일드 카드가 아니라 헤더의 화이트리스트 여야합니다.
escape-llc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.