jQuery $ .ajax (), Firefox에서 REQUEST_METHOD로“OPTIONS”를 보내는 $ .post


330

비교적 간단한 jQuery 플러그인이라고 생각했던 것에 문제가 있습니다 ...

플러그인은 ajax를 통해 PHP 스크립트에서 데이터를 가져 와서에 옵션을 추가해야합니다 <select>. 아약스 요청은 매우 일반적입니다.

$.ajax({
  url: o.url,
  type: 'post',
  contentType: "application/x-www-form-urlencoded",
  data: '{"method":"getStates", "program":"EXPLORE"}',
  success: function (data, status) {
    console.log("Success!!");
    console.log(data);
    console.log(status);
  },
  error: function (xhr, desc, err) {
    console.log(xhr);
    console.log("Desc: " + desc + "\nErr:" + err);
  }
});

이것은 Safari에서 잘 작동하는 것 같습니다. Firefox 3.5 REQUEST_TYPE에서 서버는 항상 'OPTIONS'이며 $ _POST 데이터는 나타나지 않습니다. Apache는 요청을 'OPTIONS'유형으로 기록합니다.

::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46

이 ajax 호출이 Safari에서는 작동하지만 Firefox에서는 작동하지 않는 이유는 무엇이며 Firefox에서는 어떻게 해결할 수 있습니까?

응답 헤더
날짜 : 2009 년 7 월 8 일 수요일 21:22:17 GMT
서버 : Apache / 2.0.59 (Unix) PHP / 5.2.6 DAV / 2
X-Powered-By : PHP / 5.2.6
내용 길이 46
연결 유지 시간 종료 = 15, 최대 = 100
연결 유지
컨텐츠 유형 텍스트 / html

요청 헤더
호스트 주문 양식 : 8888
User-Agent Mozilla / 5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv : 1.9.1) Gecko / 20090624 Firefox / 3.5
text / html, application / xhtml + xml, application / xml; q = 0.9, * / *; q = 0.8 수락
수락 언어 en-us, en; q = 0.5
수락 인코딩 gzip, 수축
수락 문자 ISO-8859-1, utf-8; q = 0.7, *; q = 0.7
Keep-Alive 300
연결 유지
오리진 http://ux.inetu.act.org
액세스 제어 요청 방법 POST
액세스 제어 요청 헤더 x- 요청

다음은 Firebug 출력 사진입니다.


Firebug 응답 및 요청 헤더를 게시 할 수 있습니까? Firefox에서 유사한 코드를 실행할 때 오류가 발생하지 않습니다.
MitMaro

헤더 정보와 Firebug의 사진을 추가했습니다.
fitzgeraldsteele

임베디드 웹 서버를 구현하는 동안 동일한 문제가 발생했습니다. 질문 해 주셔서 감사합니다 :)
Robert Gould

Java JAX-RS 솔루션을 찾고 있다면 여기를 참조하십시오 : Access-Control-Allow-Origin
Tobias Sarnow

파이어 폭스의 행동이 이제 바뀌었을 것 같습니다? 옵션 요청이 없습니다.
Buge

답변:


169

오류의 원인은 동일한 오리진 정책입니다. XMLHTTPRequests는 자신의 도메인에만 수행 할 수 있습니다. JSONP 콜백을 대신 사용할 수 있는지 확인하십시오 .

$.getJSON( 'http://<url>/api.php?callback=?', function ( data ) { alert ( data ); } );

26
firefox가 이것을 수행하는 유일한 브라우저 인 이유는 무엇입니까? 게시물이 필요하지 않습니다.
Maslow

11
Crossite-POST : 애플리케이션 / json을 Content-Type으로 사용하여 POST를 수행하는 솔루션을 아는 사람이 있습니까?
schoetbi

13
그렇다면 솔루션은 정확히 무엇입니까?
Nik So

3
이것에 대한 해결책도 찾고 아약스 호출 대신 getJSON을 사용하면 훨씬 제한적이므로 나에게 도움이되지 않습니다.
Timo Wallenius

1
@schoetbi는 CORS를 사용해야합니다. CORS는 최신 브라우저에서 잘 지원됩니다. IE8-9는 제한적으로 지원되며 서버 측 지원이 필요합니다.
트래커 1

57

Django 측에서 다음 코드를 사용하여 OPTIONS 요청을 해석하고 필요한 Access-Control 헤더를 설정했습니다. 그 후 Firefox의 교차 도메인 요청이 작동하기 시작했습니다. 앞에서 말했듯이 브라우저는 먼저 OPTIONS 요청을 보낸 다음 POST / GET 직후에

def send_data(request):
    if request.method == "OPTIONS": 
        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        response['Access-Control-Max-Age'] = 1000
        # note that '*' is not valid for Access-Control-Allow-Headers
        response['Access-Control-Allow-Headers'] = 'origin, x-csrftoken, content-type, accept'
        return response
    if request.method == "POST":
        # ... 

편집 : 적어도 경우에 따라 실제 응답에 동일한 Access-Control 헤더를 추가 해야하는 것으로 보입니다. 요청이 성공한 것처럼 보이기 때문에 약간 혼란 스러울 수 있지만 Firefox는 응답 내용을 Javascript로 전달하지 않습니다.


실제 POST / GET 응답에 대한 편집은 약간 무섭습니다. 누구든지 확인할 수 있으면 여기로 알려주십시오!
Arjan

나는 그것이 버그인지 또는 기능인지는 모르지만 다른 누군가도 그것을 알아 차린 것 같습니다. 예를 들어 kodemaniak.de/?p=62를 참조하고 "빈 응답 본문"을 검색 하십시오
Juha Palomäki

2
간단한 요청과 프리 플라이트가 필요한 요청에는 차이가 있습니다. "솔루션"은 프리 플라이트 요청에서만 작동하므로 실제 솔루션은 아닙니다. 요청 헤더에 "Origin :"-헤더가 표시 될 때마다 허용되는 것으로 회신해야합니다.
odinho-Velmont

1
나는 헤더 믿고 Access-Control-Allow-Headers값을 포함해야 x-csrf-token하지 x-csrftoken.
JellicleCat

16

mozilla 개발자 센터 기사 는 다양한 도메인 간 요청 시나리오를 설명합니다. 이 기사에서는 컨텐츠 유형이 'application / x-www-form-urlencoded'인 POST 요청을 '단순 요청'( '프리 플라이트'OPTIONS 요청없이)으로 보내야한다고 지적합니다. 그러나 POST가 해당 컨텐츠 유형으로 전송되었지만 Firefox가 OPTIONS 요청을 보냈습니다.

'Access-Control-Allow-Origin'응답 헤더를 '*'로 설정 한 서버에서 옵션 요청 처리기를 만들어서이 작업을 수행 할 수있었습니다. ' http://someurl.com ' 과 같이 특정 항목으로 설정하면 더 제한적일 수 있습니다 . 또한 여러 출처의 쉼표로 구분 된 목록을 지정할 수 있지만이 작업을 수행 할 수는 없다는 것을 읽었습니다.

Firefox가 허용 가능한 'Access-Control-Allow-Origin'값으로 OPTIONS 요청에 대한 응답을 받으면 POST 요청을 보냅니다.


15

전 아파치 기반 솔루션을 사용하여이 문제를 해결했습니다. 내 vhost / htaccess에서 다음 블록을 넣습니다.

# enable cross domain access control
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"

# force apache to return 200 without executing my scripts
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]

Apache가 대상 스크립트를 실행할 때 발생하는 상황에 따라 후자가 필요하지 않을 수 있습니다. 신용은 후자에 대해 친숙한 ServerFault 사람들 에게 전달됩니다.


당신의 대답은 저에게 도움이되었지만 CORS 뒤에 논리가 필요하다면 완전히 해결되지는 않습니다.
Ratata Tata

10

응답 스크립트 상단의 PHP가 작동하는 것 같습니다. (Firefox 3.6.11에서는 아직 많은 테스트를 수행하지 않았습니다.)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
if(array_key_exists('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', $_SERVER)) {
    header('Access-Control-Allow-Headers: '
           . $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
} else {
    header('Access-Control-Allow-Headers: *');
}

if("OPTIONS" == $_SERVER['REQUEST_METHOD']) {
    exit(0);
}

이것은 취향의 문제 일 수 있지만, 수 항상 그 응답 헤더를 전송하기 (위해도 GET, POST...) 조금 내 취향에 너무 많은 것입니다. (그리고 항상 전송하는 것이 사양을 준수하는지 궁금합니다.)
Arjan

3
if ($ _ SERVER [ 'HTTP_ORIGIN'])로 랩핑하십시오. 해당 헤더가 있으면 CORS 요청입니다. 그렇지 않으면 아무것도 보낼 필요가 없습니다.
odinho-Velmont

7

Google지도에 요청을 보내는 것과 동일한 문제가 있었고 jQuery 1.5를 사용하면 솔루션이 매우 간단합니다. dataType: "jsonp"


12
POST 메소드와 호환되지 않습니다.
Pavel Vlasov

1
GET 메소드와 함께 작동하지만 매우 제한된 솔루션입니다. 예를 들어 토큰을 포함하여 특정 헤더로 응답을 보낼 수 없습니다.
svassr

6

Culprit는 OPTIONS 방법을 사용한 프리 플라이트 요청입니다

사용자 데이터에 부작용을 일으킬 수있는 HTTP 요청 방법 (특히 GET 이외의 HTTP 방법 또는 특정 MIME 유형의 POST 사용)의 경우, 사양은 브라우저가 요청을 "사전 비행"하도록 요구하여 서버에서 HTTP OPTIONS 요청 메소드를 사용한 후 서버에서 "승인"하면 실제 HTTP 요청 메소드로 실제 요청을 보냅니다.

웹 사양은 https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS를 참조하십시오.

Nginx conf에 다음 줄을 추가하여 문제를 해결했습니다.

    location / {
               if ($request_method = OPTIONS ) {
                   add_header Access-Control-Allow-Origin  "*";
                   add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
                   add_header Access-Control-Allow-Headers "Authorization";
                   add_header Access-Control-Allow-Credentials  "true";
                   add_header Content-Length 0;
                   add_header Content-Type text/plain;
                   return 200;
               }
    location ~ ^/(xxxx)$ {
                if ($request_method = OPTIONS) {
                    rewrite ^(.*)$ / last;
                }
    }

1
이 답변은 매우 도움이됩니다. 브라우저가 OPTIONS 메소드로 프리 플라이트 요청을 전송한다는 사실은 명백하지 않습니다.
Normangorman

4

JSONP를 사용할 때 소스 1.3.2를 살펴보면 브라우저 동일한 도메인 정책을 통과하는 SCRIPT 요소를 동적으로 작성하여 요청합니다. 당연히 SCRIPT 요소를 사용하여 POST 요청을 할 수 없으며 브라우저는 GET을 사용하여 결과를 가져옵니다.

JSONP 호출을 요청하면 SCRIPT 요소는 AJAX 호출 유형이 GET으로 설정된 경우에만 수행되므로 SCRIPT 요소가 생성되지 않습니다.

http://dev.jquery.com/ticket/4690


4

ASP.Net에서 이와 같은 문제가 발생했습니다. $.postPageHandlerFactory로 인해 일부 HTML 콘텐츠를 가져 오기 위해 jQuery 를 실행하려고 할 때 IIS가 내부 서버 오류를 반환했습니다 GET,HEAD,POST,DEBUG. 따라서 "OPTIONS"동사를 목록에 추가하거나 "All Verbs"를 선택하여 해당 제한을 변경할 수 있습니다.

IIS 관리자에서 웹 사이트를 선택한 다음 처리기 매핑을 선택하고 필요에 따라 * .apx 파일에 대해 PageHandlerFactory를 두 번 클릭하십시오 (프레임 워크 4.0과 함께 통합 응용 프로그램 풀 사용). 요청 제한을 클릭 한 다음 동사 탭으로 이동하여 수정 사항을 적용하십시오.

이제 우리의 $.post요청이 예상대로 작동합니다 :)


2

양식의 actionURL www에 도메인 의 일부가 포함되어 있는지 확인하고 , 열려있는 원본 페이지는없이 표시 www됩니다.

일반적으로 정식 Urls ..

나는이 기사를 다루기 전에 몇 시간 동안 고생했으며 크로스 도메인의 힌트를 발견했습니다.


2

o.url = 'index.php'이 파일이 있으면 콘솔에 성공 메시지가 표시되는 것 같습니다 . url을 사용하면 오류가 반환됩니다.http://www.google.com

게시 요청을하는 경우 $ .post 메소드 를 직접 사용하지 않는 이유는 무엇입니까?

$.post("test.php", { func: "getNameAndTime" },
    function(data){
        alert(data.name); // John
        console.log(data.time); //  2pm
    }, "json");

너무 간단합니다.


이것과 같은 것을 얻었습니다 ... $ .ajax ()를 사용해야하므로 오류 상태에 대한 디버그 정보를 얻을 수 있습니다.
fitzgeraldsteele


1

이에 대한 해결책은 다음과 같습니다.

  1. dataType을 사용하십시오. json
  2. &callback=?귀하의 URL에 추가

이것은 Facebook API와 Firefox를 호출하는 데 효과적이었습니다. 위의 조건 (둘 다) GET대신 Firebug가 사용 중 OPTIONS입니다.




0

옵션을 추가하십시오 :

dataType : "json"


2
그것이 작동했는데 왜 json이 도메인 간 요청에 대해 "안전한"것으로 간주됩니까?
Nik So

0
 function test_success(page,name,id,divname,str)
{ 
 var dropdownIndex = document.getElementById(name).selectedIndex;
 var dropdownValue = document.getElementById(name)[dropdownIndex].value;
 var params='&'+id+'='+dropdownValue+'&'+str;
 //makerequest_sp(url, params, divid1);

 $.ajax({
    url: page,
    type: "post",
    data: params,
    // callback handler that will be called on success
    success: function(response, textStatus, jqXHR){
        // log a message to the console
        document.getElementById(divname).innerHTML = response;

        var retname = 'n_district';
        var dropdownIndex = document.getElementById(retname).selectedIndex;
        var dropdownValue = document.getElementById(retname)[dropdownIndex].value;
        if(dropdownValue >0)
        {
            //alert(dropdownValue);
            document.getElementById('inputname').value = dropdownValue;
        }
        else
        {
            document.getElementById('inputname').value = "00";
        }
        return;
        url2=page2; 
        var params2 = parrams2+'&';
        makerequest_sp(url2, params2, divid2);

     }
});         
}

이 질문은 6 개월 전에 이미 답변되었습니다. 이것이 어떻게 해결됩니까?
Barmar

0

Facebook API를 사용하는 데 비슷한 문제가있었습니다.

프리 플라이트 요청을 보내지 않은 유일한 contentType은 text / plain 인 것 같았습니다. 여기서 mozilla에 언급 된 나머지 매개 변수는 아닙니다.

  • 왜 이것이 유일한 브라우저입니까?
  • Facebook에서 프리 플라이트 요청을 알고 동의하지 않는 이유는 무엇입니까?

참고 : 앞에서 언급 한 Moz 문서는 X-Lori 헤더가 프리 플라이트 요청을 트리거해야한다고 제안하지만 그렇지 않습니다.


0

서버 측에서 일부 작업을 수행해야합니다. 서버 측에서 PHP를 사용하고 있지만 .NET 웹 응용 프로그램 솔루션은 다음과 같습니다 .jQuery.ajax에서 content-type을 'application / json'으로 설정할 수 없습니다

PHP 스크립트에서도 똑같이하면 작동합니다. 간단히 : 처음에는 브라우저가 서버에 요청하여 해당 유형의 데이터를 전송할 수 있는지 여부를 확인하고 두 번째 요청은 적절하거나 허용됩니다.


0

다음을 추가하십시오.

dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),  

0

다른 서버에서 호스팅되는 Apache Solr에 데이터를 게시하려고 할 때 프록시 URL을 사용하여 비슷한 문제를 해결했습니다. (완벽한 답변은 아니지만 내 문제를 해결합니다.)

이 URL을 따르십시오 : Proxying을 위해 Mode-Rewrite를 사용하여 httpd.conf에 다음 행을 추가하십시오.

 RewriteRule ^solr/(.*)$ http://ip:8983/solr$1 [P]

따라서 http : // ip : 8983 / solr / *에 데이터를 게시하는 대신 / solr에 데이터를 게시 할 수 있습니다 . 그런 다음 동일한 출처에 데이터를 게시합니다.


0

PHP에서 내 cors 상황을 잘 처리하는이 코드가 이미 있습니다.

header( 'Access-Control-Allow-Origin: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Headers: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Credentials: true' );

그리고 로컬 및 원격에서 잘 작동했지만 원격에서는 업로드하지 않았습니다.

apache / php 또는 내 코드에서 어떤 일이 발생합니다 .OPTIONS를 요청할 때 cors 규칙으로 헤더를 반환하지만 302 결과로 검색하지 않아도됩니다. 따라서 브라우저가 허용 가능한 상황으로 인식되지 않습니다.

@Mark McDonald 답변을 기반으로 한 것은 헤더 뒤에이 코드를 넣는 것입니다.

if( $_SERVER['REQUEST_METHOD'] === 'OPTIONS' )
{
    header("HTTP/1.1 202 Accepted");
    exit;
}

이제 요청 OPTIONS하면 헤더와 202 결과를 보냅니다.


-1

명심하시기 바랍니다:

JSONP는 GET 요청 방법 만 지원합니다.

* firefox로 요청 보내기 : *

$.ajax({
   type: 'POST',//<<===
   contentType: 'application/json',
   url: url,
   dataType: "json"//<<=============
    ...
});

위의 요청은 OPTIONS (==> 유형 : 'POST' )로 전송합니다 !!!!

$.ajax({
    type: 'POST',//<<===
    contentType: 'application/json',
    url: url,
    dataType: "jsonp"//<<==============
    ...
});

그러나 위의 요청은 GET으로 전송합니다 (==> 유형 : 'POST' ) !!!!

"도메인 간 통신"상태 인 경우주의를 기울이고주의하십시오.

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