Avoir des problèmes avec ce que je pensais être un plugin jQuery relativement simple ...
Le plugin devrait récupérer les données d'un script php via ajax pour ajouter des options à un <select>
. La requête ajax est assez générique:
$.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);
}
});
Cela semble bien fonctionner dans Safari. Dans Firefox 3.5, le REQUEST_TYPE
sur le serveur est toujours 'OPTIONS' et les données $ _POST n'apparaissent pas. Apache enregistre la demande sous le type 'OPTIONS':
::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46
Pourquoi cet appel ajax fonctionnerait-il dans Safari, mais pas dans Firefox, et comment puis-je le résoudre pour Firefox?
En-têtes de réponse Date: mercredi, 08 juillet 2009 21:22:17 GMT Serveur: Apache/2.0.59 (Unix) PHP/5.2.6 DAV/2 X-Powered-By: PHP/5.2.6 Contenu-Longueur 46 Délai d'attente Keep-Alive = 15, max = 100 Connexion Keep-Alive Content-Type text/html En-têtes de demande Formulaire de commande d'hôte: 8888 User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5 ; en-US; va: 1.9.1) Gecko/20090624 Firefox/3.5 Acceptez text/html, application/xhtml + xml, application/xml; q = 0,9, */*; q = 0,8 Accept-Language fr-us, en; q = 0.5 Accepter-coder gzip, deflate Accepter-Jeu de caractères ISO-8859-1, utf-8; q = 0,7, *; q = 0,7 Keep-Alive 300 Connexion de maintien en vie Origine http://ux.inetu.act.org Méthode de demande de contrôle d'accès POST En-têtes de demande de contrôle d'accès x-demandé-avec
Voici une image de la sortie de Firebug:
La raison de l'erreur est la même stratégie d'origine. Cela vous permet seulement de faire XMLHTTPRequests dans votre propre domaine. Voyez si vous pouvez utiliser un callback JSONP :
$.getJSON( 'http://<url>/api.php?callback=?', function ( data ) { alert ( data ); } );
J'ai utilisé le code suivant du côté Django pour interpréter la requête OPTIONS et définir les en-têtes de contrôle d'accès requis. Après cela, mes requêtes multi-domaines de Firefox ont commencé à fonctionner. Comme dit précédemment, le navigateur envoie d’abord la demande OPTIONS puis immédiatement après que le message 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":
# ...
Edit: il semble qu'au moins dans certains cas, vous devez également ajouter les mêmes en-têtes Access-Control à la réponse réelle. Cela peut être un peu déroutant, car la requête semble réussir, mais Firefox ne transmet pas le contenu de la réponse au Javascript.
Cet article du centre des développeurs de mozilla décrit divers scénarios de requête inter-domaines. L'article semble indiquer qu'une demande POST avec le type de contenu "application/x-www-form-urlencoded" doit être envoyée en tant que "demande simple" (sans demande OPTION de "contrôle en amont"). J'ai toutefois constaté que Firefox avait envoyé la demande OPTIONS, même si mon POST avait été envoyé avec ce type de contenu.
J'ai pu réaliser cela en créant un gestionnaire de requêtes d'options sur le serveur, définissant l'en-tête de réponse 'Access-Control-Allow-Origin-Origin' sur '*'. Vous pouvez être plus restrictif en lui attribuant une valeur spécifique, telle que ' http://someurl.com '. En outre, j'ai lu que, supposément, vous pouvez spécifier une liste d'origines multiples séparée par des virgules, mais je ne pouvais pas que cela fonctionne.
Une fois que Firefox a reçu la réponse à la demande OPTIONS avec une valeur acceptable "Accès-Contrôle-Autoriser-Origine", il envoie la demande POST.
J'ai résolu ce problème en utilisant une solution entièrement basée sur Apache. Dans mon vhost/htaccess je mets le bloc suivant:
# 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]
Vous n’avez peut-être pas besoin de cette dernière partie, en fonction de ce qui se passe lorsqu’Apache exécute votre script cible. Le mérite revient au folk ServerFault amical pour la dernière partie.
Ce PHP en haut du script de réponse semble fonctionner. (Avec Firefox 3.6.11. Je n'ai pas encore fait beaucoup de tests.)
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);
}
J'ai eu le même problème avec l'envoi de demandes à Google Maps, et la solution est très simple avec jQuery 1.5 - pour dataType, utilisez dataType: "jsonp"
Le coupable est une requête de contrôle en amont utilisant la méthode OPTIONS
Pour les méthodes de requête HTTP pouvant entraîner des effets secondaires sur les données utilisateur (en particulier pour les méthodes HTTP autres que GET ou pour l'utilisation de POST avec certains types MIME), la spécification impose aux navigateurs de "contrôler en amont" la demande. , sollicitant des méthodes prises en charge auprès du serveur avec une méthode de requête HTTP OPTIONS, puis, après "approbation" du serveur, envoyant la requête réelle avec la méthode de requête HTTP réelle.
La spécification Web fait référence à: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
J'ai résolu le problème en ajoutant les lignes suivantes dans 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;
}
}
Je cherchais dans la source 1.3.2, lorsque JSONP est utilisé, la requête est créée en créant un élément SCRIPT de manière dynamique, qui dépasse les règles de navigation des navigateurs. Naturellement, vous ne pouvez pas faire de requête POST à l'aide d'un élément SCRIPT, le navigateur extraira le résultat à l'aide de GET.
Lorsque vous demandez un appel JSONP, l'élément SCRIPT n'est pas généré car il le fait uniquement lorsque l'appel de type of AJAX est défini sur GET.
Nous avons eu un problème comme celui-ci avec ASP.Net. Notre IIS renvoyait une erreur de serveur interne lors de la tentative d'exécution d'un jQuery $.post
pour obtenir du contenu HTML dû à PageHandlerFactory étant limité à une réponse GET,HEAD,POST,DEBUG
Verbs. Vous pouvez donc modifier cette restriction en ajoutant le verbe "OPTIONS" à la liste ou en sélectionnant "Tous les verbes".
Vous pouvez modifier cela dans votre IIS Manager, en sélectionnant votre site Web, puis en sélectionnant Mappages de gestionnaires, puis double-cliquez dans votre PageHandlerFactory pour les fichiers * .apx selon vos besoins (Nous utilisons un pool d'applications intégré avec Framework 4.0). Cliquez sur Demander des restrictions, puis allez à l'onglet Verbs et appliquez votre modification.
Maintenant, notre demande $.post
fonctionne comme prévu :)
Il me semble que si o.url = 'index.php'
et que ce fichier existe est ok et renvoie un message de réussite dans la console. Il retourne une erreur si j'utilise url: http://www.google.com
Si vous faites une demande de publication, pourquoi ne pas utiliser directement la méthode $. Post :
$.post("test.php", { func: "getNameAndTime" },
function(data){
alert(data.name); // John
console.log(data.time); // 2pm
}, "json");
C'est tellement plus simple.
Vérifiez si l'URL action
de votre formulaire inclut la partie www
du domaine, tandis que la page d'origine que vous avez ouverte est affichée sans www
.
Généralement fait pour les URL canoniques.
J'ai lutté pendant des heures avant de tomber sur cet article et de trouver le soupçon de Cross Domain.
Une autre possibilité pour contourner le problème consiste à utiliser un script proxy. Cette méthode est décrite pour exemple ici
J'ai posté un exemple clair sur la façon de résoudre ce problème si vous contrôlez le code du serveur du domaine que vous publiez. Cette réponse est abordée dans ce fil de discussion, mais cela explique plus clairement cela OMI.
Comment envoyer une demande POST entre domaines à l'aide de JavaScript?
La solution à ceci est:
json
&callback=?
à votre URLcela a fonctionné en appelant l'API Facebook et avec Firefox. Firebug utilise GET
au lieu de OPTIONS
avec les conditions ci-dessus (les deux).
J'ai eu un problème similaire en essayant d'utiliser l'API Facebook.
Le seul contentType qui n'a pas envoyé la demande de contrôle en amont semblait être juste text/plain ... pas le reste des paramètres mentionnés à mozilla ici
FYI: Le document de Moz mentionné ci-dessus suggère que les en-têtes X-Lori devraient déclencher une demande de contrôle en amont ... ce n'est pas le cas.
Vous devez travailler sur le serveur. Je vois que vous utilisez PHP côté serveur, mais la solution pour l'application Web .NET est ici: Impossible de définir le type de contenu sur 'application/json' dans jQuery.ajax
Faites la même chose dans le script PHP et cela fonctionnera. Simplement: à la première requête, le navigateur demande au serveur s’il est autorisé à envoyer de telles données avec ce type et la seconde demande est correcte/autorisée.
Essayez d'ajouter ce qui suit:
dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),
J'ai déjà ce code manipulant bien ma situation de cors en php:
header( 'Access-Control-Allow-Origin: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Headers: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Credentials: true' );
Et cela fonctionnait très bien localement et à distance, mais pas pour les téléchargements à distance.
Quelque chose se passe avec Apache/php OR mon code, je n'ai pas pris la peine de le rechercher, lorsque vous demandez OPTIONS, il retourne mon en-tête avec les règles cors mais avec 302 résultats. Par conséquent, mon navigateur ne reconnaît pas la situation comme acceptable.
Ce que j'ai fait, basé sur la réponse de @Mark McDonald, est simplement de mettre ce code après mon en-tête:
if( $_SERVER['REQUEST_METHOD'] === 'OPTIONS' )
{
header("HTTP/1.1 202 Accepted");
exit;
}
Maintenant, en demandant OPTIONS
, il n'enverra que l'en-tête et le résultat.
Pouvez-vous essayer ceci sans
contentType:application/x-www-form-urlencoded
Essayez d'ajouter l'option:
dataType: "json"
J'ai utilisé une URL de proxy pour résoudre un problème similaire lorsque je souhaite publier des données sur mon serveur Apache hébergé sur un autre serveur. (Cela peut ne pas être la réponse parfaite mais cela résout mon problème.)
Suivez cette URL: tilisation de Mode-Rewrite pour le proxy , j'ajoute cette ligne à mon httpd.conf:
RewriteRule ^solr/(.*)$ http://ip:8983/solr$1 [P]
Par conséquent, je peux simplement poster des données sur/solr au lieu de poster des données sur http: // ip: 8983/solr / *. Ensuite, il affichera des données dans la même origine.
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);
}
});
}