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


465

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 속성에 의해 제어됩니다.

답변:


821

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

  • 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포함 Authorization하고 Content-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_inURL이 무엇이든 대체됩니다 .

브라우저가 해당 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"상태 코드로 응답합니다.

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

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

  • 서버가 Authorization요청 헤더를 요구하지 않고 대신 POST요청 본문에 내장 된 인증 데이터 또는 쿼리 매개 변수에 의존 하는 경우
  • 서버에 POST본문에 Content-Type: application/json미디어 유형 이 필요하지 않지만 대신 JSON 데이터 값 을 갖는 매개 변수 (또는 기타)를 사용 하여 POST본문을 수락 한 경우application/x-www-form-urlencodedjson

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

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

요청의 자격 증명 모드가 '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응답 헤더 의 값으로 에코 / 반영하는 서버를 구성하는 것 입니다. 예를 들어, 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-*헤더는 응답 헤더. 당신은 요청에 그들을 보내고 싶지 않습니다. 필요한 유일한 효과는 프리 플라이트를 수행하도록 브라우저를 트리거하는 것입니다.


1
URL은 다음과 같습니다. 127.0.0.1:9999/127.0.0.1:5000 cors, 맞습니까?
daniel.lozynski

당신은 당신의 자신의 인스턴스를 실행하는 경우 github.com/Rob--W/cors-anywhere의 에서 코드 127.0.0.1:9999를 당신은에 요청을 만들고 싶어 127.0.0.1:5000 , 네
sideshowbarker을

4
최고의 대답, 내 문제는 원격 서버가 그래서 헤더를 제거하여 해결 나이 같게 보였던 것을 요청과 헤더에 대한 조롱 후, OPTIONS 요청에 응답하지 않았다 Content-TypeAccess-Control-Allow-Origin- 감사합니다!
Morvael

1
프록시를 사용하는 것이 아니라면 프록시를 사용하는 아이디어가 마음에 들지 않습니다. 그렇지 않으면 신뢰할 수없는 제 3자를 통해 데이터를 가져오고 변조 할 수 있습니다.
DaveMongoose

1
심층적이고 훌륭한 답변입니다. 테스트 할 때 개인적으로 수행 한 작업은 웹 비활성화 보안 플래그가있는 Open chrome이며 작동했습니다. open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
Karun

101

이 오류는 포트 번호를 포함하여 클라이언트 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

4
아무 문제없이 일했습니다 ... 봄 자원 링크에 매우 도움이되었습니다. 감사합니다
Rajesh Mbm

4
including the port number:(
scottysseus

1
정말 도움이 U 하루를 만들었습니다
kunal 친구

포트 번호는 내 생명을 구했습니다
ashad

가장 간단한 답변 덕분에 :)
스택

46

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

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

4
이것은 최고의 답변이어야합니다. 특히 CORS를 우회하는 아이디어, 특히 타사를 통해 라우팅하는 것을 싫어합니다.
DaveMongoose

안녕하세요, 'Header ()'란 무엇입니까?
mitsu

@mitsu 라인을 참조하면 : let headers = new Headers (); 위의 경우 http 요청 또는 응답 헤더로 작업을 수행하는 것은 인출 API의 인터페이스입니다. developer.mozilla.org/en-US/docs/Web/API/Headers 를 방문 하여 자세한 내용과 사용 예를 확인하십시오.
Lex Soft

1
명확하고 정확한 답변. 논리적이고 정확하게 문제를 해결합니다. -Thx
Dhammika

7

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

프런트 엔드 또는 앵귤러

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);

2

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

백엔드에서 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/*})



1

사용하는 dataType: 'jsonp'날 위해 일했습니다.

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you
                                    //       just specify dataType: jsonp
                                    return data;
                                }
                            });


 } // function               

1

제 경우에는 웹 서버가 "OPTIONS"방법을 막았습니다

옵션 방법은 웹 서버를 확인하십시오.

"웹 티어"를 사용하고 있습니다

/ www / webtier / domains / [도메인 이름] /config/fmwconfig/components/OHS/VCWeb1/httpd.conf

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>

로 변경

<IfModule mod_rewrite.c>
  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>

0

Spring REST로 작업하고 있었고 WebMvcConfigurer에 AllowedMethods를 추가하여 해결했습니다.

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }

-1

내 지역 에서이 오류가 발생했습니다. Visual Studio를 관리자로 실행하여 해결했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.