Odpowiedzi:
Nie jest możliwe wykonanie asynchronicznej POST
usługi w innej domenie ze względu na (całkiem rozsądne) ograniczenie tej samej zasady pochodzenia . JSON-P działa tylko dlatego, że możesz wstawiać<script>
tagi do DOM i mogą one wskazywać gdziekolwiek.
Możesz oczywiście uczynić stronę w innej domenie akcją zwykłego formularza POST.
Edycja : Istnieje kilka interesujących hacków , jeśli chcesz włożyć dużo wysiłku, wstawiając ukryte <iframe>
litery i manipulując ich właściwościami.
POST
żądania do innych domen, o ile zarówno ta domena, jak i Twoja przeglądarka obsługują CORS
. Ale to całkowicie prawda POST
i JSONP
nie są kompatybilne.
<script>
tagów wskazujących na inną domenę. Jedynym sposobem wykonania żądań POST w przeglądarce jest użycie formularzy HTML lub XMLHttpRequest.
Jeśli potrzebujesz przesłać dużo danych między domenami. Zwykle tworzę usługę, do której możesz zadzwonić w dwóch krokach:
Najpierw klient przesyła FORMULARZ (przesyłanie dozwolone między domenami). Usługa przechowuje dane wejściowe sesji na serwerze (używając identyfikatora GUID jako klucza). (klient tworzy identyfikator GUID i wysyła go jako część danych wejściowych)
Następnie klient wykonuje zwykłe wstrzyknięcie skryptu (JSONP) jako parametr, którego używasz tego samego identyfikatora GUID, który został użyty w poście FORMULARZA. Usługa przetwarza dane wejściowe z sesji i zwraca dane w normalnym trybie JSONP. Po tym sesja jest niszczona.
Zależy to oczywiście od tego, że napiszesz zaplecze serwera.
XMLHttpRequest
nie powinien być w ogóle zaangażowany. W odpowiedzi Per wykorzystuje zwykłe przesłanie formularza do żądania POST, a następnie wstrzyknięcie elementu skryptu w celu wykonania żądania GET.
Wiem, że to poważna nekromancja, ale pomyślałem, że opublikuję moją implementację JSONP POST przy użyciu jQuery, którego z powodzeniem używam do mojego widgetu JS (służy do rejestracji i logowania klienta):
Zasadniczo używam podejścia IFrame, zgodnie z sugestią zawartą w zaakceptowanej odpowiedzi. Inaczej robię po wysłaniu zapytania, obserwuję, czy do formularza można dotrzeć w ramce iframe, używając timera. Gdy formularz nie jest dostępny, oznacza to, że żądanie zostało zwrócone. Następnie używam zwykłego żądania JSONP, aby zapytać o stan operacji.
Mam nadzieję, że komuś się przyda. Przetestowano w> = IE8, Chrome, FireFox i 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;
}
Ogólnie rzecz biorąc, JSONP jest implementowane przez dodanie pliku <script>
tagu do wywołującego dokumentu, tak że adres URL usługi JSONP to „src”. Przeglądarka pobiera źródło skryptu z transakcją HTTP GET.
Teraz, jeśli Twoja usługa JSONP znajduje się w tej samej domenie, co strona wywołująca, prawdopodobnie możesz coś połączyć za pomocą prostego $.ajax()
połączenia. Jeśli nie znajduje się w tej samej domenie, nie jestem pewien, jak byłoby to możliwe.
CORS
, będzie to możliwe, o ile przeglądarka również ją obsługuje. W takich przypadkach użyjesz zwykłego JSON
zamiast JSONP
.
Przy użyciu tego projektu można użyć serwera proxy CORS . Skierowałoby cały ruch do punktu końcowego w Twojej domenie i przekazałby te informacje do domeny zewnętrznej. Ponieważ przeglądarka rejestruje wszystkie żądania w tej samej domenie, możemy wysyłać JSON. UWAGA: Działa to również z certyfikatami SSL przechowywanymi na serwerze.
Istnieje (hack) rozwiązanie. Robiłem to wiele razy, będziesz mógł publikować za pomocą JsonP. (Będziesz mógł wysłać formularz, większy niż 2000 znaków, niż możesz użyć przez GET)
Aplikacja kliencka Javascript
$.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);
}
});
JAWA:
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');
Robiąc w ten sposób, otwierasz swój serwer na każde żądanie postu, powinieneś ponownie zabezpieczyć to, podając identyfikator lub coś innego.
Dzięki tej metodzie możesz również zmienić typ żądania z jsonp na json, oba działają, po prostu ustaw odpowiedni typ zawartości odpowiedzi
jsonp
response.setContentType( "text/javascript; charset=utf-8" );
json
response.setContentType( "application/json; charset=utf-8" );
Proszę nie, że twój serwer nie będzie już przestrzegać SOP (tej samej polityki pochodzenia), ale kogo to obchodzi?
<script>
tagów do swojego HTML DOM (do diabła, możesz ich nawet używać w aplikacjach komputerowych, powiedzmy, że chcesz wysłać wiele żądań JSON do tego samego serwera i chcesz użyć nazwy funkcji na przykład jako identyfikator śledzenia żądań).
Jest to możliwe, oto moje rozwiązanie:
W twoim javascript:
jQuery.post("url.php",data).complete(function(data) {
eval(data.responseText.trim());
});
function handleRequest(data){
....
}
W twoim url.php:
echo "handleRequest(".$responseData.")";