모드에서 페치 및 전달 사용 : no-cors


167

http://catfacts-api.appspot.com/api/facts?number=99Postman을 통해이 끝점을 칠 수 있습니다.JSON

또한 create-react-app를 사용하고 있으며 서버 구성을 설정하지 않으려 고합니다.

내 클라이언트 코드 fetch에서 동일한 작업을 수행 하려고 하지만 오류가 발생합니다.

요청 된 리소스에 'Access-Control-Allow-Origin'헤더가 없습니다. 따라서 원본 ' http : // localhost : 3000 '은 액세스 할 수 없습니다. 불투명 한 응답이 사용자의 요구를 충족시키는 경우 요청 모드를 'no-cors'로 설정하여 CORS가 비활성화 된 상태에서 리소스를 가져옵니다.

그래서 객체를 CORS를 비활성화하는 Fetch로 전달하려고합니다.

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

흥미롭게도 내가 얻는 오류는 실제로이 함수의 구문 오류입니다. fetch{mode : 'no-cors'} 객체를 제거하고 다른 URL을 제공하면 제대로 작동하기 때문에 실제 고장이 확실하지 않습니다 .

또한 객체를 전달하려고했지만 { mode: 'opaque'}위의 원래 오류를 반환합니다.

CORS를 사용하지 않도록 설정하기 만하면됩니다. 무엇을 놓치고 있습니까?

답변:


292

mode: 'no-cors'마술처럼 작동하지 않습니다. 사실, 브라우저에 "프론트 엔드 JavaScript 코드가 모든 상황에서 응답 본문과 헤더의 내용을 보지 못하도록 차단" 하는 효과가 있기 때문에 상황이 악화 됩니다. 물론 당신은 거의 그것을 원하지 않습니다.

프론트 엔드 JavaScript의 출처 간 요청에서 발생하는 일은 기본적으로 브라우저가 프론트 엔드 코드가 자원 간 출처에 액세스하는 것을 차단한다는 것입니다. Access-Control-Allow-Origin응답에 있으면 브라우저는 해당 차단을 완화하고 코드가 응답에 액세스 할 수 있도록합니다.

그러나 사이트 Access-Control-Allow-Origin가 응답을 보내지 않으면 프런트 엔드 코드는 해당 사이트의 응답에 직접 액세스 할 수 없습니다. 특히, 지정하여 문제를 해결할 수 없습니다 mode: 'no-cors'(것 사실 확인 응답 내용을 액세스 할 수 없습니다 귀하의 프론트 엔드 코드).

그러나 한 가지 효과 있습니다. CORS 프록시를 통해 요청을 보내면 다음 과 같이됩니다.

var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
    targetUrl = 'http://catfacts-api.appspot.com/api/facts?number=99'
fetch(proxyUrl + targetUrl)
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    document.querySelector("pre").innerHTML = JSON.stringify(data, null, 2);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });
<pre></pre>

참고 : https://cors-anywhere.herokuapp.com을 사용하려고 할 때 다운 된 경우 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 .


http://catfacts-api.appspot.com/api/facts?number=99Postman을 통해이 엔드 포인트에 도달 할 수 있습니다

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 는 Postman으로 응답에 액세스 할 수 있지만 브라우저가 프런트 엔드에서 응답 교차 출처에 액세스 할 수없는 이유를 설명합니다. 응답에 Access-Control-Allow-Origin응답 헤더가 포함되어 있지 않으면 웹앱에서 실행되는 JavaScript 코드 입니다.

http://catfacts-api.appspot.com/api/facts?number=99 에는 Access-Control-Allow-Origin응답 헤더 가 없으므로 프런트 엔드 코드가 응답 교차 출처에 액세스 할 수있는 방법이 없습니다.

브라우저가 응답을 잘 얻을 수 있으며 Postman 및 브라우저 devtools에서도 볼 수 있지만 브라우저가 코드에 노출되는 것은 아닙니다. Access-Control-Allow-Origin응답 헤더 가 없기 때문에 그렇지 않습니다 . 따라서 대신 프록시를 사용해야합니다.

프록시는 해당 사이트에 요청을하고 응답을 받고 Access-Control-Allow-Origin응답 헤더와 필요한 다른 CORS 헤더를 추가 한 다음 요청 코드로 다시 전달합니다. Access-Control-Allow-Origin헤더가 추가 된 응답 은 브라우저에 표시되므로 브라우저는 프론트 엔드 코드가 실제로 응답에 액세스 할 수 있도록합니다.


CORS를 비활성화하는 Fetch에 객체를 전달하려고합니다.

당신은 그렇게하고 싶지 않습니다. 분명히, CORS를 비활성화하고 싶다고 말하면 실제로 동일한 출처 정책 을 비활성화하려는 것 같습니다 . CORS 자체는 실제로이를 수행하는 방법입니다. CORS는 동일 출처 정책을 제한하는 방법이 아닌 완화하는 방법입니다.

그러나 어쨌든 로컬 환경에서만 브라우저 런타임 플래그를 지정하여 보안을 비활성화하고 안전하지 않게 실행하는 것과 같은 작업을 수행하거나 로컬에서 브라우저 확장을 설치하여 동일한 출처 정책을 해결할 수는 있지만 당신만을 위해 상황을 바꾸는 것입니다.

로컬로 무엇을 변경하더라도 앱을 사용하려는 다른 사람은 여전히 ​​동일한 출처 정책을 실행할 수 있으며 다른 앱 사용자를 위해이를 비활성화 할 수있는 방법이 없습니다.

당신 mode: 'no-cors'은 거의 제한된 경우를 제외하고는 실제로 사용하고 싶지 않을 것입니다. 심지어 당신이하고있는 일과 그 효과가 무엇인지 정확히 알고있는 경우에만 가능합니다. mode: 'no-cors'브라우저에서 실제로 설정 하는 내용은 "모든 상황에서 프론트 엔드 JavaScript 코드가 응답 본문 및 헤더의 내용을 보지 못하도록 차단하기"때문입니다. 대부분의 경우 그것은 분명히 당신이 원하는 것이 아닙니다.


지금까지의 경우처럼 당신이 경우 것이다 사용을 고려할 mode: 'no-cors'의 대답을 참조하십시오 제한이 불투명 한 응답에 적용 어떻게? 자세한 내용은. 요점은 다음과 같습니다.

  • 당신이에 다른 원점에서 컨텐츠를 넣어 자바 스크립트를 사용하고 제한된 경우 <script>, <link rel=stylesheet>, <img>, <video>, <audio>, <object>, <embed>, 또는 <iframe>하지만 어떤 이유로 당신이 '돈 - (자원의 내장 출처 간 그 허용되기 때문에 작동) 요소 t이 원하는하거나 문서 사용의 마크 업을 자원은 AS URL함으로써 그렇게 할 수 없습니다 href또는 src요소의 속성을.

  • 리소스로 수행하려는 유일한 작업은 리소스를 캐시하는 것입니다. 답변에서 언급했듯이 불투명 한 응답 에는 어떤 제한이 적용됩니까? 실제로 적용되는 시나리오는 서비스 워커를 사용하는 경우입니다.이 경우 관련 API캐시 스토리지 API 입니다.

그러나 이러한 제한된 경우에도 알아야 할 몇 가지 중요한 문제가 있습니다. 불투명 한 응답어떤 제한이 적용됩니까? 의 답변을 참조하십시오 . 자세한 내용은.


나는 또한 물건을 전달하려고했습니다. { mode: 'opaque'}

mode: 'opaque'요청 모드 는 없습니다. opaque대신 응답 의 속성 일 뿐이며 브라우저는 해당 no-cors모드 와 함께 전송 된 요청의 응답에 대해 불투명 한 속성을 설정 합니다.

그러나 우연히 opaque 라는 단어 는 응답의 본질에 대한 명백한 신호입니다.“opaque”는 볼 수 없다는 의미입니다.


4
cors-anywhere간단한 비 유용한 사용 사례 (즉, 공개적으로 사용 가능한 데이터 가져 오기)에 대한 해결 방법을 좋아하십시오 . 이 답변은 no-corsOpaqueResponse가 그다지 유용하지 않기 때문에 일반적이지 않은 내 의심을 확인 합니다. 즉, "매우 제한된 경우"; 누구든지 유용한 예제 를 나 에게 설명 할 수 no-cors있습니까?
The Red Pea

1
@TheRedPea 여기에 대한 답변에 대한 업데이트를 확인하십시오 (그리고 stackoverflow.com/questions/52569895/… 에서 귀하의 질문에 대한 코멘트로 추가했습니다 )
sideshowbarker

- 나는 CORS.js 패키지 내 Express 서버를 구성하는 데 필요한 github.com/expressjs/cors - 그리고 나는 제거하기 위해 필요 mode: 'no-cors'(그렇지 않으면 응답이 빈 것) 페치 요청에서
제임스 L.를

CORS 프록시는 훌륭합니다. 공개 파일에 대한 액세스를 차단하는 "보안"수단으로 간주된다는 사실에 놀랐습니다. 해커 관점에서 쉽게 돌아 다닐 수 있으며 이것이 바로 그렇게합니다. 좋은 배우에게는 정말 번거 롭습니다.
Seph Re '10

동일한 API를 사용하는 다른 클라이언트의 코드를 생성합니다. 나는 훈련에 사용합니다. 코드를 단순하게 유지하고 사용자가 코드를 가지고 놀도록하고 싶습니다. 노크로를 사용해야합니다.
profimedica

6

Laravel API에서 데이터를 가져 와서 Vue 프론트 엔드에서 사용하려고하는 localhost에서 웹 사이트를 개발하고 있다면이 문제를 보는 방법은 다음과 같습니다.

  1. Laravel 프로젝트에서 command를 실행하십시오. php artisan make:middleware Cors . 이것은 app/Http/Middleware/Cors.php당신 을 위해 만들 것입니다.
  2. handles함수 안에 다음 코드를 추가하십시오 Cors.php.

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  3. 에서 app/Http/kernel.php, 다음 항목 추가 $routeMiddleware배열을 :

    cors => \App\Http\Middleware\Cors::class

    (같은 배열의 다른 항목이있을 것입니다 auth, guest또한 당신이이 일을했는지 확인 등 app/Http/kernel.php다른 있기 때문에kernel.php 너무 Laravel에서)

  4. 다음과 같이 액세스를 허용하려는 모든 경로에 대해 경로 등록시이 미들웨어를 추가하십시오.

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
  5. Vue 프론트 엔드에서이 API를 호출 mounted()하지 말고 함수로 호출하십시오 data(). 또한 통화 에서 http://또는 https://URL을 사용하십시오 fetch().

Pete Houston의 블로그 기사에 대한 전체 크레딧 .


2

간단한 해결책 : 데이터를 요청하는 PHP 파일의 맨 위에 다음을 추가하십시오.

header("Access-Control-Allow-Origin: *");


8
가능한 한 적은 양의 보안을 원할 경우 매우 좋습니다. :).
Heretic Monkey

이미지 핫 링크는
어떻습니까

1

나를위한 해결책은 서버 측에서만하는 것이 었습니다

C # WebClient라이브러리를 사용하여 데이터 (내 경우에는 이미지 데이터)를 가져 와서 클라이언트로 다시 보냈습니다. 선택한 서버 측 언어와 매우 유사한 것이있을 수 있습니다.

//Server side, api controller

[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
    ItemImage image = new ItemImage();

    using(WebClient client = new WebClient()){

        image.Bytes = client.DownloadData(url);

        return Ok(image);
    }
}

자신의 유스 케이스에 관계없이 조정할 수 있습니다. 요점은 client.DownloadData()CORS 오류없이 작동합니다. 일반적으로 CORS 문제는 웹 사이트간에 만 발생하므로 서버에서 '사이트 간'요청을해도됩니다.

그런 다음 React 페치 호출은 다음과 같이 간단합니다.

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise<ItemImage>)
    .then(imgResponse => {

       // Do more stuff....
    )}

1

매우 쉬운 솔루션 (구성에 2 분)은 로컬 SSL 프록시 패키지를 사용하는 것입니다.npm

사용법은 매우 간단합니다.
1. 패키지를 설치합니다 : npm install -g local-ssl-proxy
2. local-server마스크를 사용 하여 마스크를 실행하는 동안local-ssl-proxy --source 9001 --target 9000

추신 : 교체 --target 9000-- "number of your port"--source 9001함께--source "number of your port +1"


1
실제 휴대 전화 기기에서 앱을 사용하는 데 문제가 있습니다. 이 경우 솔루션이 도움이 되나요?
하미드 아라 기

@HamidAraghi 저는 개발 목적으로 프록시 서버가 실제로 오류의 영향을받는 장치에서 실행되어야한다고 생각합니다
volna
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.