JsonP에 데이터 게시


102

JsonP에 데이터를 게시 할 수 있습니까? 아니면 모든 데이터가 GET 요청으로 쿼리 문자열에 전달되어야합니까?

서비스, ​​도메인 간 전송해야하는 데이터가 많고 쿼리 문자열을 통해 전송하기에는 너무 큽니다.

이 문제를 해결하기위한 옵션은 무엇입니까?

답변:


83

동일한 출처 정책POST 의 (상당히 합리적인) 제한으로 인해 다른 도메인의 서비스에 대해 비동기를 수행하는 것은 불가능합니다 . JSON-P 는 DOM에 태그 를 삽입 할 수 있고 어디든 가리킬 수 있기 때문에 작동합니다 .<script>

물론 다른 도메인의 페이지를 일반 형식 POST의 작업으로 만들 수 있습니다.

편집 : 숨겨진 s를 삽입 하고 속성을 비웃는 데 많은 노력을 기울이고 싶다면 흥미로운 해킹<iframe>있습니다.


"비동기 POST"가 불가능하다고 말씀 하셨는데 .... 동기 POST를 수행 할 수 있습니까?
Mark

4
@mark "동기 POST"는 <form method = "post"action = "http : // ... / ...">를 사용하는 양식 제출을 의미합니다.
Steven Kryskalla 2011 년

8
이것은 사실이 아닙니다. POST해당 도메인과 브라우저가 모두 지원하는 한 다른 도메인에 대한 요청을 확실히 수행 할 수 있습니다 CORS. 그러나 그것은 완전히 사실 POST이며 JSONP양립 할 수 없습니다.
hippietrail

2
JSONP는 <script>다른 도메인을 가리키는 태그를 삽입하여 구현됩니다 . 브라우저에서 POST 요청을 실행하는 유일한 방법은 HTML 양식 또는 XMLHttpRequest를 사용하는 것입니다.
friedo

1
(일반적으로-) 다른 도메인의 서비스에 비동기 POST를 수행하는 것이 가능합니다. 제한은 응답에 있습니다. 제한은 JSONP 요청에도 있습니다.
Royi Namir 2014

20

많은 데이터를 도메인 간 전송해야하는 경우. 일반적으로 두 단계로 호출 할 수있는 서비스를 만듭니다.

  1. 먼저 클라이언트는 FORM 제출 (포스트 허용 교차 도메인)을 수행합니다. 서비스는 서버의 세션에 입력을 저장합니다 (GUID를 키로 사용). (클라이언트는 GUID를 생성하고 입력의 일부로 보냅니다)

  2. 그런 다음 클라이언트는 FORM 게시물에서 사용한 것과 동일한 GUID를 사용하는 매개 변수로 일반 스크립트 삽입 (JSONP)을 수행합니다. 서비스는 세션의 입력을 처리하고 일반 JSONP 방식으로 데이터를 반환합니다. 이 후 세션이 파괴됩니다.

물론 이것은 서버 백엔드를 작성하는 것에 달려 있습니다.


1
당신의 앞치마를 시도했습니다. FF14 및 Chrome20에서 작동했습니다. Opera11과 IE9는 게시물을 전송하지 않았습니다. (디버그 도구로 확인하고 다른 쪽 서버에서 들었습니다.) IE의 장애와 관련이있을 수있는 질문은 다음과 같습니다. stackoverflow.com/questions/10395803/… 콘솔에 Chrome 불만이 있지만 여전히 POST를 수행했습니다. XMLHttpRequest는 할 수 없습니다. load localhost : 8080 / xxx Origin null은 Access-Control-Allow-Origin에서 허용되지 않습니다.
OneWorld 2012

@OneWorld — 답변이 말한대로하지 않았습니다. XMLHttpRequest전혀 관여해서는 안됩니다. Per의 답변은 일반 양식 제출을 사용하여 POST 요청을 한 다음 스크립트 요소 삽입을 사용하여 GET 요청을 만듭니다.
Quentin

7

나는 이것이 심각한 강령술이라는 것을 알고 있지만 jQuery를 사용하여 JSONP POST 구현을 게시 할 것이라고 생각했는데, 이는 JS 위젯에 성공적으로 사용하고 있습니다 (고객 등록 및 로그인에 사용됨).

기본적으로 수락 된 답변에서 제안한 것처럼 IFrame 접근 방식을 사용하고 있습니다. 내가 다르게하는 것은 요청을 보낸 후 타이머를 사용하여 iframe에서 양식에 도달 할 수 있는지 확인하는 것입니다. 양식에 도달 할 수없는 경우 요청이 반환되었음을 의미합니다. 그런 다음 정상적인 JSONP 요청을 사용하여 작업 상태를 쿼리합니다.

누군가가 유용하다고 생각하기를 바랍니다. > = IE8, Chrome, FireFox 및 Safari에서 테스트되었습니다.

function JSONPPostForm(form, postUrl, queryStatusUrl, queryStatusSuccessFunc, queryStatusData)
{
    var tmpDiv = $('<div style="display: none;"></div>');
    form.parent().append(tmpDiv);
    var clonedForm = cloneForm(form);
    var iframe = createIFrameWithContent(tmpDiv, clonedForm);

    if (postUrl)
        clonedForm.attr('action', postUrl);

    var postToken = 'JSONPPOST_' + (new Date).getTime();
    clonedForm.attr('id', postToken);
    clonedForm.append('<input name="JSONPPOSTToken" value="'+postToken+'">');
    clonedForm.attr('id', postToken );
    clonedForm.submit();

    var timerId;
    var watchIFrameRedirectHelper = function()
    {
        if (watchIFrameRedirect(iframe, postToken ))
        {
            clearInterval(timerId);
            tmpDiv.remove();
            $.ajax({
                url:  queryStatusUrl,
                data: queryStatusData,
                dataType: "jsonp",
                type: "GET",
                success: queryStatusSuccessFunc
            });
        }
    }

    if (queryStatusUrl && queryStatusSuccessFunc)
        timerId = setInterval(watchIFrameRedirectHelper, 200);
}

function createIFrameWithContent(parent, content)
{
    var iframe = $('<iframe></iframe>');
    parent.append(iframe);

    if (!iframe.contents().find('body').length)
    {
        //For certain IE versions that do not create document content...
        var doc = iframe.contents().get()[0];
        doc.open();
        doc.close();
    }

    iframe.contents().find('body').append(content);
    return iframe;
}

function watchIFrameRedirect(iframe, formId)
{
    try
    {
        if (iframe.contents().find('form[id="' + formId + '"]').length)
            return false;
        else
            return true;
    }
    catch (err)
    {
        return true;
    }
    return false;
}

//This one clones only form, without other HTML markup
function cloneForm(form)
{
    var clonedForm = $('<form></form>');
    //Copy form attributes
    $.each(form.get()[0].attributes, function(i, attr)
    {
        clonedForm.attr(attr.name, attr.value);
    });
    form.find('input, select, textarea').each(function()
    {
        clonedForm.append($(this).clone());
    });

    return clonedForm;
}

4

일반적으로 JSONP는 <script>JSONP 서비스의 URL이 "src"가되도록 호출 문서에 태그를 추가하여 구현됩니다 . 브라우저는 HTTP GET 트랜잭션으로 스크립트 소스를 가져옵니다.

이제 JSONP 서비스가 호출 페이지와 동일한 도메인에있는 경우 간단한 $.ajax()호출로 무언가를 결합 할 수 있습니다. 같은 도메인에 있지 않다면 어떻게 가능한지 잘 모르겠습니다.


이 경우 동일한 도메인에 있지 않습니다. 그리고 나는 GET 만 가능하다고 가정하고 있지만 오늘 JsonP에 대해 읽기 시작했고 그것이 내가 필요한 것에 적합한 지에 대한 결정을 내릴 필요가 있기 때문에 확인하고 싶었습니다
ChrisCa

2
동일한 도메인에 있지 않지만 지원 CORS하는 경우 브라우저도 지원하는 한 가능합니다. 이러한 경우에는 보통 사용 JSON하는 대신 JSONP.
hippietrail

예, @hippietrail 2 년은 큰 차이를 만듭니다. :-) CORS는 확실히 가능하지만 물론 데이터 소스를 적절하게 설정해야합니다.
Pointy

0

프로젝트 를 사용하여 CORS 프록시 를 사용할 수 있습니다 . 모든 트래픽을 도메인의 엔드 포인트로 전달하고 해당 정보를 외부 도메인으로 릴레이합니다. 브라우저가 모든 요청을 동일한 도메인에 등록하기 때문에 JSON을 게시 할 수 있습니다. 참고 : 이는 서버에있는 SSL 인증서에서도 작동합니다.


-1

여러 번 해본 (해킹) 솔루션이 있습니다. JsonP로 게시 할 수 있습니다. (GET에서 사용할 수있는 것보다 2000 자 이상인 양식을 게시 할 수 있습니다.)

클라이언트 애플리케이션 자바 스크립트

$.ajax({
  type: "POST", // you request will be a post request
  data: postData, // javascript object with all my params
  url: COMAPIURL, // my backoffice comunication api url
  dataType: "jsonp", // datatype can be json or jsonp
  success: function(result){
    console.dir(result);
  }
});

자바:

response.addHeader( "Access-Control-Allow-Origin", "*" ); // open your api to any client 
response.addHeader( "Access-Control-Allow-Methods", "POST" ); // a allow post
response.addHeader( "Access-Control-Max-Age", "1000" ); // time from request to response before timeout

PHP :

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');

이렇게하면 모든 게시 요청에 대해 서버를 열고 ident 또는 다른 것을 제공하여이를 다시 보호해야합니다.

이 방법을 사용하면 요청 유형을 jsonp에서 json으로 변경할 수도 있습니다. 둘 다 작동하고 올바른 응답 콘텐츠 유형을 설정하기 만하면됩니다.

jsonp

response.setContentType( "text/javascript; charset=utf-8" );

json

response.setContentType( "application/json; charset=utf-8" );

서버가 더 이상 SOP (동일한 원산지 정책)를 존중하지 않지만 누가 신경 쓰나요?


이것은 CORS가있는 AJAX가 아닙니다. AJAX는 XML을 사용하고 있음을 의미합니다. CORS를 사용한 JSON [P]입니다. JSONP는 "패딩"이있는 "JSON"입니다. 패딩에 대한 함수 호출로 래핑 된 JSON 데이터를 전송하는 경우 CORS가있는 JSONP입니다. <script>HTML DOM에 태그를 삽입하는 것 외에 JSON 및 JSONP 데이터 표기법을 모두 사용할 수 있습니다 (데스크톱 앱에서도 사용할 수 있습니다. 동일한 서버에 여러 JSON 요청을하고 함수 이름을 사용하고 싶다고 가정 해 보겠습니다.) 예를 들어 요청 추적 ID).
BrainSlugs83 2014 년

-6

가능합니다. 여기 내 해결책이 있습니다.

자바 스크립트에서 :

jQuery.post("url.php",data).complete(function(data) {
    eval(data.responseText.trim()); 
});
function handleRequest(data){
    ....
}

url.php에서 :

echo "handleRequest(".$responseData.")";

11
이 경우 jQuery는 설명서에 따라 요청을 Get으로 전환했을 가능성이 높습니다. 참고 : 이렇게하면 POST를 원격 도메인 요청에 대한 GET으로 전환합니다. api.jquery.com/jQuery.ajax
월드
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.