GET 요청 대신 OPTIONS 요청을받는 이유는 무엇입니까?


288
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) {
     alert(data);
});
</script>

해당 URL에 대한 OPTIONS 요청을 수행 한 다음 콜백이 아무 것도 호출되지 않습니다.

교차 도메인이 아닌 경우 제대로 작동합니다.

jQuery가 <script>노드로 호출 한 다음로드 될 때 콜백을 수행 해서는 안 됩니까? 도메인 간이므로 결과를 얻을 수는 없지만 문제는 없습니다. 그냥 전화를 걸고 싶어 이것은 버그입니까, 아니면 내가 잘못하고 있습니까?


2
교차 도메인의 cos 일 수 있습니다. 예를 들어 localhost / WEBSITE_LINK를 사용하는 대신 File : // PATH_TO_WEBSITE 파일에있는 경우
James111

답변:


262

에 따르면 MDN ,

사전 요청

위에서 설명한 간단한 요청과 달리, "미리 비행 된"요청은 실제 요청이 안전하게 전송되는지 확인하기 위해 먼저 다른 도메인의 리소스에 HTTP OPTIONS 요청 헤더를 보냅니다. 사이트 간 요청은 사용자 데이터에 영향을 줄 수 있으므로 이와 같이 프리 플라이트됩니다. 특히 다음과 같은 경우 요청이 프리 플라이트됩니다.

  • GET 또는 POST 이외의 메소드를 사용합니다. 또한 POST를 사용하여 application / x-www-form-urlencoded, multipart / form-data 또는 text / plain 이외의 Content-Type으로 요청 데이터를 보내는 경우 (예 : POST 요청이 서버에 XML 페이로드를 보내는 경우) application / xml 또는 text / xml을 사용하면 요청이 프리 플라이트됩니다.
  • 요청에 사용자 정의 헤더를 설정합니다 (예 : 요청에 X-PINGOTHER와 같은 헤더가 사용됨)

43
이 문제는 "application / json"에서 "text / plain"으로
바뀌면서

10
내가 이해하지 못하는 것은 브라우저가 실제 요청이 전송하는 것이 안전한지 확인하기 위해 OPTIONS 방법으로 요청하는 이유입니다. 그러나 어떤 의미에서? 서버가 특정 응답 헤더에 제한을 둘 수 있으므로 이것이 왜 필요한가요?
hardik

11
@hardik CORS를 추가하면 다른 사람의 요청을 받아 들일 수 있으며 요청 (POST, PUT, DELETE 등)을 통해 서버의 데이터를 조작 할 수 있습니다. 이러한 상황에서 사용자 지정 헤더를 사용할 때와 같이 브라우저는 요청하지 않은 요청을 서버에 보내는 것이 데이터에 위험 할 수 있으므로 서버가 요청을 수락하기 전에 서버가 먼저 서버와 요청을 수락하는지 확인합니다. 서버가 페이로드를 수락하지 않으려는 경우 브라우저에서 잠재적으로 큰 페이로드를 전송하는 지점이므로 비행 전 OPTIONS 검사.
davidnknight

6
@davidnknight 서버로 데이터를 전송하는 것이 위험 할 수있는 경우 서버가 손상 될 수 있음을 의미합니다. 물론 악의적 인 서버는 "Sure, all it send all!"으로 OPTIONS 요청에 응답합니다. 보안은 어떻습니까? (정직한 질문)
Matt

3
"비행 요청은 보안이 아닙니다. 오히려 규칙을 바꾸지 않는 것입니다." - 프리 플라이트 요청을 소개하는 동기 부여에
FMJaguar


9

POST 하려는 경우

JSON.stringify양식 데이터 를 확인 하고로 보내십시오 text/plain.

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() {

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) {
        obj[item.name] = item.value;
        return obj;
    }, {});
    formData = JSON.stringify(formData);

    $.ajax({
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function() { ... },
        dataType: "text",
        contentType : "text/plain"
    });
}

2

jQuery가 URL을 제공 할 때 JSONP 요청을 자연스럽게 수행한다고 생각하지 않습니다. 그러나 콜백에 사용할 인수를 알려 주면 JSONP 요청을 수행합니다.

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) {
     alert(data);
});

해당 인수 ( "jsoncallback"이라고 불릴 필요는 없음)를 사용하는 것은 전적으로 수신 스크립트에 달려 있으므로이 경우 함수는 호출되지 않습니다. 그러나 당신은 당신이 metaward.com에서 스크립트를 실행하기를 원한다고 말했기 때문에 그렇게 할 것입니다.


스크립트 요소가 완전히로드되었다는 알림 메시지가 계속 표시됩니까? API를 쿼리하기 전에 업데이트가 발생했는지 확인하고 싶습니다.
Paul Tarjan

수신 스크립트가 JSONP를 지원하고 식별하는 함수를 기꺼이 호출 할 것입니다. 스크립트가 다른 동작없이 JSON 데이터 블록 만 생성하는 경우로드가 완료된 시점을 알 수 없습니다. 로드가 완료된 시점을 알려야하는 경우 프록시 역할을하는 자체 서버에서 스크립트를 구현하는 것을 고려할 수 있습니다.
VoteyDisciple

1

실제로, 보안상의 이유로 도메인 간 AJAX (XMLHttp) 요청은 허용되지 않습니다 (클라이언트 측에서 "제한된"웹 페이지를 가져 와서 서버로 다시 보내는 것에 대해 생각하십시오. 이것은 보안 문제 일 것입니다).

유일한 해결 방법은 콜백입니다. 이것은 새로운 스크립트 객체를 생성하고 src를 JSON 값 (myFunction ({data})을 사용하는 콜백 인 end-side JavaScript를 가리 키도록합니다. myFunction은 데이터와 관련하여 무언가를 수행하는 함수입니다 (예 : 저장) 변수에서).


1
맞습니다.하지만 <script src = ""> 또는 <img src = "">에로드하면 브라우저가 행복하게 맞출 것입니다. 가져 오기 결과를 쿼리 할 수 ​​있도록 완전히로드 된 시점을 알고 싶습니다.
Paul Tarjan

1

"application / json"을 "text / plain"으로 변경하고 JSON.stringify (요청)을 잊지 마십시오.

var request = {Company: sapws.dbName, UserName: username, Password: userpass};
    console.log(request);
    $.ajax({
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    });

1

나는 같은 문제가 있었다. 내 수정은 dev 환경에있을 때만 존재하는 PHP 스크립트에 헤더를 추가하는 것이 었습니다.

이를 통해 도메인 간 요청이 가능합니다.

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

이는 프리 플라이트 요청에 클라이언트가 원하는 헤더를 보내도된다는 것을 알려줍니다.

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

이런 식으로 요청을 수정할 필요가 없습니다.

잠재적으로 유출 될 수있는 민감한 데이터가 dev 데이터베이스에 있다면, 이것에 대해 두 번 생각할 수 있습니다.


1

필자의 경우 동일한 웹 서버에 jQuery POST를 발행했기 때문에 문제는 CORS와 관련이 없습니다. 데이터는 JSON이지만 dataType : 'json'매개 변수를 생략했습니다.

위의 David Lopes의 답변에 표시된 것처럼 contentType 매개 변수가 없거나 추가하지 않았습니다.


0

Firefox 및 Opera (Mac에서도 테스트 됨)는 크로스 도메인을 좋아하지 않지만 (Safari는 괜찮습니다).

원격 페이지를 말리려면 로컬 서버 측 코드를 호출해야 할 수도 있습니다.


0

다음 헤더를 사용하여 문제를 해결할 수있었습니다.

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

Nodejs를 사용하는 경우 복사 / 붙여 넣을 수있는 코드는 다음과 같습니다.

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.