Chrome의 AJAX가 GET / POST / PUT / DELETE 대신 옵션을 전송합니까?


107

직장에서 내부 웹 응용 프로그램을 작업 중입니다. IE10에서는 요청이 제대로 작동하지만 Chrome에서는 모든 AJAX 요청 (많은 경우)이 내가 제공하는 정의 된 방법 대신 OPTIONS를 사용하여 전송됩니다. 기술적으로 내 요청은 "교차 도메인"입니다. 이 사이트는 localhost : 6120에서 제공되며 AJAX 요청을하는 서비스는 57124에 있습니다. 이 닫힌 jquery 버그 는 문제를 정의하지만 실제 수정은 아닙니다.

ajax 요청에서 적절한 http 메소드를 사용하려면 어떻게해야합니까?

편집하다:

이것은 모든 페이지의 문서로드에 있습니다.

jQuery.support.cors = true;

그리고 모든 AJAX는 유사하게 구축됩니다.

var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
    url: url,
    dataType: "json",
    data: json,
    async: true,
    cache: false,
    timeout: 30000,
    headers: { "x-li-format": "json", "X-UserName": userName },
    success: function (data) {
        // my success stuff
    },
    error: function (request, status, error) {
        // my error stuff
    },
    type: "POST"
});

2
그 버그 리포트의 마지막 코멘트 ... 꽤 잘 설명
케빈 B에게

1
내가하는 모든 것이 너무 바닐라이기 때문에 내 마음이 뒤집 혔습니다 (내 코드는 jquery 버그의 코드와 유사합니다). 그 외에도 그것을 포함하지 않은 것에 대한 변명의 여지가 없습니다. BRB, 샘플 코드를 가져 왔습니다.
Corey Ogburn

3
IE는 요청이 교차 출처인지 결정할 때 포트 번호를 고려하지 않습니다.
Ray Nicholus

@KevinB : REST 서비스는 http 메서드를 기반으로 다른 작업을 수행하는 것처럼 다양한 요청을 활용합니다. 모든 것을 GET으로 전환하는 것은 유효한 수정이 아닙니다. 또한 Dark Falcon의 답변에 따르면 요청에 X-UserName 및 기타 사용자 정의 헤더가 있기 때문에 어쨌든 도움이되지 않습니다.
Corey Ogburn

출처 간 요청을하려면 출처 간 요청에 적용되는 모든 규칙을 따라야 제대로 작동한다는 사실은 변하지 않습니다. 교차 출처 요청에는 일반적으로 OPTIONS 요청이 포함됩니다. 제대로 처리하면 문제가 사라집니다. 이 문제를 해결하는 유일한 다른 방법 (api 변경없이)은 서버 측 코드를 사용하여 API와 상호 작용하는 기본 페이지와 동일한 서버에 스크립트를 두는 것입니다.
Kevin B

답변:


136

Chrome은 CORS 헤더 를 찾는 요청을 프리 플라이트하고 있습니다. 요청이 허용되면 실제 요청을 보냅니다. 이 교차 도메인을 수행하는 경우 단순히 처리하거나 요청을 비 교차 도메인으로 만드는 방법을 찾아야합니다. 이것이 jQuery 버그가 수정되지 않는 것처럼 닫힌 이유입니다. 이것은 의도적으로 설계된 것입니다.

간단한 요청 (위에서 설명)과 달리 "프리 플라이트 된"요청은 실제 요청을 보내는 것이 안전한지 여부를 확인하기 위해 먼저 OPTIONS 메서드에 의해 다른 도메인의 리소스에 HTTP 요청을 보냅니다. 교차 사이트 요청은 사용자 데이터에 영향을 미칠 수 있으므로 이와 같이 미리 실행됩니다. 특히 다음과 같은 경우 요청이 프리 플라이트됩니다.

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

20
사용자 정의 헤더. 그것이 아마도 preflight OPTIONS 호출을 설정하는 것입니다.
Corey Ogburn

18

요청 이 기본 포트 80/443에서 전송되지 않는다는 사실을 기반 으로이 Ajax 호출은 자동으로 CORS (Cross-Origin Resource) 요청으로 간주됩니다. 즉, 요청이 다음을 확인하는 OPTIONS 요청을 자동으로 발행 함을 의미합니다. 서버 / 서블릿 측의 CORS 헤더.

이것은 당신이 설정 한 경우에도 발생합니다

crossOrigin: false;

또는 생략하더라도.

그 이유는 단순히 localhost != localhost:57124. localhost포트없이 전송 해보 십시오. 요청 된 대상에 도달 할 수 없기 때문에 실패합니다. 그러나 도메인 이름이 같으면 POST 전에 OPTIONS 요청없이 요청이 전송됩니다.


3

나는 Kevin B에 동의합니다. 버그 보고서에 모든 것이 나와 있습니다. 도메인 간 ajax 호출을 시도하는 것 같습니다. 동일한 출처 정책에 익숙하지 않은 경우 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript에서 시작할 수 있습니다. .

이것이 교차 도메인 아약스 호출이 아닌 경우 대상 URL을 상대적으로 만들고 문제가 해결되는지 확인하십시오. JSONP를 절실히 들여다보고 있지만 조심하면 혼란이 숨어 있습니다. 당신을 돕기 위해 우리가 할 수있는 일이별로 없습니다.


1
우리의 시스템 구조는 변경할 수 없습니다. 다른 포트를 사용하는 것은 우리 아키텍처의 요구 사항입니다. 나는 동일한 출처 정책을 얻었지만 우리가 구현 한 CORS로 충분하다고 생각했습니다. 분명히 아닙니다.
Corey Ogburn

2
서버가 JSON 응답을 반환하는 경우 JSONP 메서드를 살펴보고 책임감있게 사용하면됩니다.
jgitter

1
나는 당신과 논쟁을 벌이고 싶지 않지만 JSONP는 스크립트 태그를 사용하여 다른 도메인에서 데이터를 가져온 다음 그 결과를 콜백 함수로 보냅니다. 결과가 json이 아니면 훨씬 더 어렵습니다.
jgitter

1
아니, 그다지 어렵지 않습니다. 실제로 응답은 어떤 경우에도 유효한 JSON이 아니어야합니다. 대신 서버는 다음과 같은 것을 반환해야합니다 callbackfunc(somedata).. 보시다시피 이것은 유효한 JSON이 아닙니다. 그리고, somedata문자열, 숫자 또는 원하는 것이 될 수 있습니다.
Ray Nicholus

1
Postman을 사용하고 있으며 요청 방법이 올바르게 전송됩니다 (예 : 'PUT', 'DELETE'등). 하지만 내 코드에서 시도 할 때 항상 요청 메서드 OPTIONS와 함께 보냅니다. Postman이 어떻게 할 수 있는지 모르겠습니다.
ErwinGO

1

가능하다면 다른 이름의 일반 GET / POST를 통해 매개 변수를 전달하고 서버 측 코드에서 처리하도록합니다.

CORS를 우회하기 위해 내 프록시와 비슷한 문제가 있었고 Chrome에서 POST-> OPTION과 동일한 오류가 발생했습니다. 그것은 Authorization내 경우 의 헤더 였습니다 ( "x-li-format"그리고 "X-UserName"귀하의 경우에는 여기에 있습니다.) 결국 더미 형식 (예 : AuthorizatinJackGET)으로 전달하고 목적지에 대한 호출을 할 때 프록시의 코드를 헤더로 바꾸도록 변경했습니다. . 다음은 PHP입니다.

if (isset($_GET['AuthorizationJack'])) {
    $request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}

1

제 경우에는 AWS (API Gateway)에서 호스팅하는 API를 호출하고 있습니다. API 자체 도메인이 아닌 도메인에서 API를 호출하려고 할 때 오류가 발생했습니다. API 소유자이기 때문에 다음에 설명 된대로 테스트 환경에 대해 CORS를 활성화했습니다. Amazon 설명서에 .

프로덕션에서는 요청과 API가 동일한 도메인에 있기 때문에이 오류가 발생하지 않습니다.

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


0

으로 대답 @Dark 팔콘, 나는 간단하게 처리 .

제 경우에는 node.js 서버를 사용하고 있고 존재하지 않으면 세션을 생성합니다. OPTIONS 메서드에는 세션 세부 정보가 없기 때문에 모든 POST 메서드 요청에 대해 새 세션이 생성되었습니다.

그래서 내 앱 루틴에서 create-session-if-not-exist인지 확인하기 위해 메서드가 있는지 확인하고 OPTIONS그렇다면 세션 생성 부분을 건너 뜁니다.

    app.use(function(req, res, next) {
        if (req.method !== "OPTIONS") {
            if (req.session && req.session.id) {
                 // Session exists
                 next();
            }else{
                 // Create session
                 next();
          }
        } else {
           // If request method is OPTIONS, just skip this part and move to the next method.
           next(); 
        }
    }


0

axios 사용 고려

axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {

  if(res.data.error) {

  } else { 
    doAnything( res.data )
  }

}).catch(function (error) {
   doAnythingError(error)
});

나는 fetch 와 axios를 사용 하여이 문제가 완벽하게 작동했습니다.


5
Axios는 첫 번째 옵션도 사용합니다
Skylin R

0

매우 유사한 문제가 발생했습니다. Firefox에서 모든 것이 올바르게 작동하고 Chrome에서 실패하는 이유를 이해하기 위해 거의 반나절을 보냈습니다. 제 경우에는 요청 헤더의 중복 된 (또는 잘못 입력 된) 필드 때문이었습니다.


0

XHR 대신 가져 오기를 사용하면 요청이 교차 도메인이더라도 사전 조명되지 않습니다.


-1
 $.ajax({
            url: '###',
            contentType: 'text/plain; charset=utf-8',
            async: false,
            xhrFields: {
                withCredentials: true,
                crossDomain: true,
                Authorization: "Bearer ...."
            },

            method: 'POST',

            data: JSON.stringify( request ),
            success: function (data) {
                console.log(data);
            }
        });

contentType : 'text / plain; charset = utf-8 '또는 contentType :'text / plain '이 저에게 적합합니다! 문안 인사!!


이것이 질문과 어떤 관련이 있습니까?
Corey Ogburn

안녕하세요, 제목의 문제가 해결되었다고 생각합니다.이 콘텐츠 유형은 OPTIONS 메서드를 전달합니다. 감사합니다
데이빗 로페스

ContentType은 메서드와 관련이 없습니다.
Corey Ogburn

나는 당신이 말하는 것을 알고 있지만 시도해보십시오. 브라우저에 따라 콘텐츠 유형이 요청에 영향을 미치고 방법을 변경할 수 있습니다!
David Lopes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.