REST API에서 데이터를 가져 오려고 할 때 요청 된 자원에 'Access-Control-Allow-Origin'헤더가 없습니다.

javascript api cors fetch-api preflight


HP Alm의 REST API에서 일부 데이터를 가져 오려고합니다. 작은 curl 스크립트와 잘 작동합니다. 데이터를 얻습니다.

이제 JavaScript를 사용하여 가져 오는 것과 가져 오기 및 ES6 (더 많거나 적은)이 더 큰 문제인 것 같습니다. 이 오류 메시지가 계속 나타납니다.

Fetch API가로드 할 수 없습니다. 프리 플라이트 요청에 대한 응답이 액세스 제어 확인을 통과하지 못함 : 요청 된 리소스에 'Access-Control-Allow-Origin'헤더가 없습니다. 따라서 원본 ' http://127.0.0.1:3000 '은 액세스 할 수 없습니다. 응답의 HTTP 상태 코드는 501입니다. 불투명 한 응답이 사용자의 요구에 부응하는 경우 CORS가 비활성화 된 상태에서 리소스를 가져 오려면 요청 모드를 'no-cors'로 설정하십시오.

로컬 호스트 내에서 해당 데이터를 가져 오려고하기 때문에 솔루션이 CORS를 사용해야하기 때문에 이것이 이해됩니다. 이제 실제로 그렇게했다고 생각했지만 어떻게 든 헤더에 쓰는 것을 무시하거나 문제가 다른 것입니까?

그렇다면 구현 문제가 있습니까? 내가 잘못하고 있습니까? 불행히도 서버 로그를 확인할 수 없습니다. 나는 정말로 여기 붙어 있습니다.

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Chrome을 사용하고 있습니다. Chrome CORS 플러그인을 사용해 보았지만 다른 오류 메시지가 나타납니다.

요청의 자격 증명 모드가 'include'인 경우 응답의 'Access-Control-Allow-Origin'헤더 값이 와일드 카드 '*'가 아니어야합니다. 따라서 원본 ' http://127.0.0.1:3000 '은 액세스 할 수 없습니다. XMLHttpRequest에 의해 시작된 요청의 자격 증명 모드는 withCredentials 속성에 의해 제어됩니다.




Answer 1 sideshowbarker


이 답변은 많은 근거를 다루므로 세 부분으로 나뉩니다.

  • CORS 프록시를 사용하여 “No Access-Control-Allow-Origin header” 문제를 해결하는 방법
  • CORS 프리 플라이트를 피하는 방법
  • 어떻게 해결하는 "액세스 제어 - 허용 - 원산지 헤더는 와일드 카드가 아니어야합니다" 문제

CORS 프록시를 사용하여 “No Access-Control-Allow-Origin header” 문제를 해결하는 방법

프론트 엔드 JavaScript 코드가 요청을 보내는 서버를 제어하지 않고 해당 서버의 응답에 문제가있어 필요한 Access-Control-Allow-Origin 헤더가없는 경우에도 작업을 수행 할 수 있습니다. CORS 프록시를 통해 요청합니다. 작동 방식을 보여주기 위해 먼저 CORS 프록시를 사용하지 않는 코드가 있습니다.

const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

catch 블록에 도달 하는 이유는 브라우저가 해당 코드가 https://example.com 에서 오는 응답에 액세스하지 못하도록하기 때문 입니다. 그리고 브라우저가 그렇게하는 이유는 응답에 Access-Control-Allow-Origin 응답 헤더가 없습니다.

이제 정확히 동일한 예이지만 CORS 프록시가 추가 된 것입니다.

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

참고 : https://cors-anywhere.herokuapp.com을 다운로드 할 때 다운되었거나 사용할 수없는 경우 2-3 분만에 Heroku에 자체 CORS Anywhere 서버를 배포하는 방법은 아래를 참조하십시오.

위의 두 번째 코드 스 니펫은 요청 URL을 가져 와서 프록시 URL을 접두사로 사용 하여 https://cors-anywhere.herokuapp.com/https://example.com으로 변경하기 때문에 응답에 성공적으로 액세스 할 수 있습니다 . 해당 프록시를 통해 요청하면 다음과 같습니다.

  1. 요청을 https://example.com 으로 전달합니다 .
  2. https://example.com 으로부터 응답을받습니다 .
  3. 추가 Access-Control-Allow-Origin 응답에 헤더를.
  4. 추가 된 헤더와 함께 해당 응답을 요청 프론트 엔드 코드로 다시 전달합니다.

그런 다음 브라우저는 프론트 엔드 코드가 응답에 액세스 할 수있게합니다. Access-Control-Allow-Origin 응답 헤더가있는 응답이 브라우저에 표시 되기 때문입니다 .

https://github.com/Rob--W/cors-anywhere/의 코드를 사용하여 자신의 프록시를 쉽게 실행할 수 있습니다 .
5 개의 명령으로 말 그대로 2-3 분만에 Heroku에 자신의 프록시를 쉽게 배포 할 수 있습니다.

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

해당 명령을 실행하면 https://cryptic-headland-94862.herokuapp.com/ 과 같은 자체 CORS Anywhere 서버가 실행됩니다 . 따라서 요청 URL 앞에 https://cors-anywhere.herokuapp.com 을 접두사로 붙이지 말고 대신 자신의 인스턴스 URL로 접두사를 붙이십시오 . 예를 들어, https://cryptic-headland-94862.herokuapp.com/https://example.com .

따라서 https://cors-anywhere.herokuapp.com을 사용하려고 할 때 다운되어 있음을 발견 한 경우 (아직 사용하지 않는 경우) Heroku 계정을 가져 와서 2를 가져 오는 것을 고려하십시오. 또는 3 분 동안 위 단계를 수행하여 Heroku에 자신의 CORS Anywhere 서버를 배포하십시오.

자체적으로 실행하든 https://cors-anywhere.herokuapp.com 또는 기타 개방형 프록시를 사용하든 상관없이이 솔루션은 브라우저가 CORS 프리 플라이트 OPTIONS 요청 을 수행하도록 요청 하는 브라우저 인 경우에도 작동합니다 . 프록시는 또한 프리 플라이트 성공에 필요한 Access-Control-Allow-HeadersAccess-Control-Allow-Methods 헤더를 다시 보냅니다 .


CORS 프리 플라이트를 피하는 방법

문제의 코드는 Authorization 헤더를 전송하기 때문에 CORS 프리 플라이트를 트리거합니다 .

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

그럼에도 불구하고 Content-Type: application/json 헤더도 프리 플라이트를 트리거합니다.

브라우저가 시도하기 전에 : 무엇 "프리 플라이트"수단 POST 를 질문의 코드에서, 그것은 먼저 보내드립니다 OPTIONS 크로스 - 기원 수신에 서버가 사용 중단 된 경우 결정 - 서버에 요청 POST 을 포함 AuthorizationContent-Type: application/json 헤더.

작은 curl 스크립트와 잘 작동합니다. 데이터를 얻습니다.

curl 로 올바르게 테스트하려면 브라우저가 전송 하는 프리 플라이트 OPTIONS 요청을 에뮬레이트해야합니다 .

curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
    -H 'Access-Control-Request-Method: POST' \
    -H 'Access-Control-Request-Headers: Content-Type, Authorization' \
    "https://the.sign_in.url"

https://the.sign_in.url 실제 sign_in URL로 바꿉니다 .

OPTIONS 요청 에서 브라우저가 볼 수있는 응답 에는 다음과 같은 헤더가 포함되어야합니다.

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

경우 OPTIONS 반응은 그 헤더를 포함하지 않는, 브라우저는 바로 거기 중지 결코 심지어 전송을 시도 POST 의 요청을. 또한 응답의 HTTP 상태 코드는 2xx (일반적으로 200 또는 204) 여야합니다. 다른 상태 코드 인 경우 브라우저가 바로 중지됩니다.

받는 질문에 서버가 응답 OPTIONS 분명히 지원 구현하지 않습니다 표시하려고 의미 501 상태 코드로 요청 OPTIONS 요청을. 이 경우 다른 서버는 일반적으로 405 "Method not allowed"상태 코드로 응답합니다.

따라서 서버 가 405 또는 501 또는 200 또는 204 이외의 다른 OPTIONS 으로 해당 OPTIONS 요청에 응답하거나 응답하지 않으면 프런트 엔드 JavaScript 코드에서 해당 서버로 직접 POST 요청 을 할 수 없습니다. 필요한 응답 헤더.

문제의 사례에 대한 프리 플라이트를 유발하지 않는 방법은 다음과 같습니다.

  • 서버가 Authorization 요청 헤더를 요구하지 않고 대신 (예를 들어) POST 요청 의 본문에 내장 된 인증 데이터 또는 쿼리 매개 변수에 의존 하는 경우
  • 서버가 POST 본문에 Content-Type: application/json 미디어 유형을 요구하지 않고 대신 json (또는 무엇이든) 이라는 매개 변수를 사용 하여 POST 본문을 application/x-www-form-urlencoded 로 승인 한 경우 JSON 데이터

어떻게 해결하는 "액세스 제어 - 허용 - 원산지 헤더는 와일드 카드가 아니어야합니다" 문제

다른 오류 메시지가 나타납니다.

요청의 자격 증명 모드가 'include'인 경우 응답의 'Access-Control-Allow-Origin'헤더 값이 와일드 카드 '*'가 아니어야합니다. 따라서 원본 ' http://127.0.0.1:3000 '은 액세스 할 수 없습니다. XMLHttpRequest에 의해 시작된 요청의 자격 증명 모드는 withCredentials 속성에 의해 제어됩니다.

신임 정보가 포함 된 요청의 경우, Access-Control-Allow-Origin 응답 헤더의 값이 * 인 경우 브라우저는 프론트 엔드 JavaScript 코드가 응답에 액세스하지 못하게합니다 . 대신에이 값은 프론트 엔드 코드의 출처 인 http://127.0.0.1:3000 과 정확히 일치해야합니다 .

참조 자격있는 요청과 와일드 카드 MDN이 HTTP 액세스 제어 (CORS) 기사를.

요청을 보내는 서버를 제어하는 ​​경우이 경우를 처리하는 일반적인 방법은 서버에서 Origin 요청 헤더 의 값을 가져 와서 서버를 Access-Control-Allow-Origin 의 값으로 에코 / 반영하는 것입니다. Control-Allow-Origin 응답 헤더. 예를 들어, nginx의 경우 :

add_header Access-Control-Allow-Origin $http_origin

그러나 이것은 하나의 예일뿐입니다. 다른 (웹) 서버 시스템은 원점 값을 반향하는 유사한 방법을 제공합니다.


Chrome을 사용하고 있습니다. 또한 그 Chrome CORS 플러그인을 사용해 보았습니다.

Chrome CORS 플러그인은 분명히 브라우저가 보는 응답에 Access-Control-Allow-Origin: * 헤더를 간단하게 주입합니다 . 플러그인이 더 똑똑하다면, 가짜 가짜 Access-Control-Allow-Origin 응답 헤더 의 값을 프론트 엔드 JavaScript 코드의 실제 출처 ( http://127.0.0.1:3000 )로 설정하면 됩니다.

따라서 테스트에도 플러그인을 사용하지 마십시오. 산만입니다. 브라우저에서 응답을 필터링하지 않고 서버에서 어떤 응답을 얻는 지 테스트하려면 위와 같이 curl -H 를 사용하는 것이 좋습니다 .


질문 의 fetch(…) 요청에 대한 프론트 엔드 JavaScript 코드는 다음과 같습니다.

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

그 줄을 제거하십시오. Access-Control-Allow-* 헤더는 응답 헤더. 당신은 요청에 그들을 보내지 않으려는. 유일한 효과는 프리 플라이트를 수행하도록 브라우저를 트리거하는 것입니다.




Answer 2 Rakesh


이 오류는 포트 번호를 포함하여 클라이언트 URL과 서버 URL이 일치하지 않을 때 발생합니다. 이 경우 교차 출처 자원 공유 인 CORS에 대해 서비스를 활성화해야합니다.

Spring REST 서비스를 호스팅하는 경우 Spring Framework 의 블로그 게시물 CORS 지원에서 찾을 수 있습니다 .

Node.js 서버를 사용하여 서비스를 호스팅하는 경우

  1. Node.js 서버를 중지하십시오.
  2. npm install cors --save
  3. server.js에 다음 줄을 추가하십시오.

    var cors = require('cors')
    
    app.use(cors()) // Use this after the variable declaration



Answer 3 Lex Soft


프론트 엔드에서 요청 헤더 로 다음 코드를 추가했기 때문에 문제가 발생했습니다 .

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

이러한 헤더는 요청이 아닌 response 에 속합니다 . 따라서 라인을 포함하여 제거하십시오 .

headers.append('GET', 'POST', 'OPTIONS');

귀하의 요청에 'Content-Type : application / json'이 있었으므로 CORS 프리 플라이트가 트리거되었습니다. 이로 인해 브라우저가 OPTIONS 메소드로 요청을 보냈습니다. 자세한 내용은 CORS 프리 플라이트 를 참조하십시오.
따라서 백엔드 에서는 다음을 포함하는 응답 헤더를 반환하여이 프리 플라이트 요청을 처리해야합니다.

Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept

물론 실제 구문은 백엔드에 사용하는 프로그래밍 언어에 따라 다릅니다.

프런트 엔드에서는 다음과 같아야합니다.

function performSignIn() {
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Basic ' + base64.encode(username + ":" +  password));
    headers.append('Origin','http://localhost:3000');

    fetch(sign_in, {
        mode: 'cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}



Answer 4 Harrison O


내 경우에는 아래 솔루션을 사용합니다.

프런트 엔드 또는 앵귤러

post(
    this.serverUrl, dataObjToPost,
    {
      headers: new HttpHeaders({
           'Content-Type':  'application/json',
         })
    }
)

백엔드 (PHP를 사용합니다)

header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);



Answer 5 Yair Levy


CORS 프록시를 사용하여“No Access-Control-Allow-Origin header”문제를 해결 하는 방법에 관한 2 센트

백엔드에서 PHP로 작업하는 사람들을 위해 "CORS 프록시"를 배포하는 것은 다음과 같이 간단합니다.

  1. 다음 내용으로 'no-cors.php'라는 파일을 만듭니다.

    $URL = $_GET['url']; echo json_encode(file_get_contents($URL)); die();

  2. 프론트 엔드에서 다음과 같이하십시오.

    fetch('https://example.com/no-cors.php' + '?url=' + url) .then(response=>{*/Handle Response/*})