Le Prototype de requête AJAX étant envoyé en option plutôt qu'EN GET; entraîne une erreur de 501

j'essaie d'accéder à un service Web avec Prototype/AJAX et je suis en train de courir dans une erreur que je ne peux pas comprendre: il semble que lorsque je fais une requête à un serveur ma requête est interprétée comme une option plutôt qu'une requête GET (et à son tour jette une erreur 501 - not implemented puisque le serveur ne permet les requêtes GET, basé sur ce que je comprends de Access-Control-Request-Method: ). Est-ce que je manque quelque chose dans ma formulation AJAX/request qui pourrait être à l'origine de cette erreur? J'ai lu un peu en La SCRO/contrôlé les demandes ici mais je ne suis pas sûr de savoir comment il pourrait s'appliquer lorsque mon code est conforme...

Voici la demande AJAX pertinente:

function fetchMetar() {
var station_id = $("station_input").value;

    new Ajax.Request(REQUEST_ADDRESS, {
        method: "get",
        parameters: {stationString: station_id},
        onSuccess: displayMetar,
        onFailure: function() {
            $("errors").update("an error occurred");
        }
    });
}

et voici l'erreur et les informations de requête pertinentes que je reçois de Chrome:

Request URL:http://weather.aero/dataserver_current/httpparam?
 dataSource=metars&requestType=retrieve&format=xml&hoursBeforeNow=3
 &mostRecent=true&stationString=&stationString=KSBA
Request Method:OPTIONS
Status Code:501 Not Implemented
Request Headers
Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:origin, x-prototype-version, x-requested-with, accept
Access-Control-Request-Method:GET
Connection:keep-alive
Host:weather.aero
Origin:http://domain.com
Referer:http://domain.com/.../...html

Qu'est-ce que je pourrais ignorer ici? Pourquoi Chrome dit-il que la requête est envoyée en option plutôt qu'EN GET? Lorsque Chrome crache les informations Access-Control-Request-Headers: , sont ces exclusivement les têtes autorisés dans la demande?

Merci!

7
demandé sur Philip David 2012-12-11 10:20:27

4 réponses

trop d'heures à chercher une solution correcte sur prototypejs... enfin, nous avons une solution non-intrusive sur grand kourge (Wilson Lee) article !. En voici un extrait:

la plupart des cadres Ajax majeurs aiment définir des en-têtes HTTP personnalisés sur les requêtes Ajax que vous instanciez; l'en-tête le plus populaire est X-Requested-With: XMLHttpRequest. Par conséquent, votre demande est promue à une version pré-allumée et échoue. La solution est d' empêchez votre framework JavaScript de définir ces en-têtes personnalisés si votre demande est un cross-domain one. jQuery évite déjà astucieusement les requêtes de préflighting non intentionnelles en ne définissant pas les en-têtes personnalisés si votre URL est considérée comme distante. Vous devez empêcher cela manuellement si vous utilisez d'autres cadres.

il peut être si simple que:

new Ajax.Request('http://www.external-domain.net/my_api.php?getParameterKey=getParameterValue', {
            method:'post',
            contentType:"application/x-www-form-urlencoded",
            postBody:'key=' + value,
            onSuccess: function(response) {
                // process response
            },
            onCreate: function(response) { // here comes the fix
                var t = response.transport; 
                t.setRequestHeader = t.setRequestHeader.wrap(function(original, k, v) { 
                    if (/^(accept|accept-language|content-language)$/i.test(k)) 
                        return original(k, v); 
                    if (/^content-type$/i.test(k) && 
                        /^(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)(;.+)?$/i.test(v)) 
                        return original(k, v); 
                    return; 
                }); 
            } 
        });

si vous voyez un inconvénient / amélioration à cette solution, nous bienvenue à vous faire partager :)

14
répondu Katapofatico 2013-03-08 17:39:57

en fait , il s'agit de demande de vol avant , parce que Prototype ajoute des en-têtes personnalisés X-demandé-avec, X-Prototype-Version à la demande. En raison de ces en-têtes, le navigateur envoie d'abord la demande OPTIONS . XHR spec says:

pour les requêtes non-same origin utilisant la méthode HTTP GET une requête pré-Light est faite lorsque des en-têtes autres que Accept et Accept-Language sont définis.

Comment résoudre ce problème? Je ne vois qu'une seule possibilité de résoudre ce problème dès que possible: remplacer complètement la méthode Ajax.Request#setRequestHeaders() , par exemple insérer ce script juste après le Prototype.js:

Ajax.Request.prototype.setRequestHeaders = function() {
  var headers = {
    // These two custom headers cause preflight request:
    //'X-Requested-With': 'XMLHttpRequest',
    //'X-Prototype-Version': Prototype.Version,
    'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
  };

  if (this.method == 'post') {
    headers['Content-Type'] = this.options.contentType +
      (this.options.encoding ? '; charset=' + this.options.encoding : '');

    /* Force "Connection: close" for older Mozilla browsers to work
     * around a bug where XMLHttpRequest sends an incorrect
     * Content-length header. See Mozilla Bugzilla #246651.
     */
    if (this.transport.overrideMimeType &&
        (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
          headers['Connection'] = 'close';
  }

  if (typeof this.options.requestHeaders == 'object') {
    var extras = this.options.requestHeaders;

    if (Object.isFunction(extras.push))
      for (var i = 0, length = extras.length; i < length; i += 2)
        headers[extras[i]] = extras[i+1];
    else
      $H(extras).each(function(pair) { headers[pair.key] = pair.value; });
  }

  for (var name in headers)
    this.transport.setRequestHeader(name, headers[name]);
}

ce patch supprime les en-têtes personnalisés de toute requête AJAX. Dans le cas où vous avez encore besoin de ces en-têtes pour les requêtes non-CORS, plus de logique peut être ajoutée qui donnera la possibilité de désactiver ces en-têtes dans les options pour new Ajax.Request() (je vais sauter cette variante ici pour faire une réponse courte.

6
répondu Victor 2012-12-11 19:24:20

en fait, C'est beaucoup plus facile avec un Prototype.js V1.7:

Ajax.Responders.register({
    onCreate:function(r){
        r.options.requestHeaders={
        'X-Prototype-Version':null,
        'X-Requested-With':null
        };
    }
});

Prototype.js supprime tout en-tête prédéfini si sa valeur est nulle.

1
répondu rumpel 2015-09-02 10:48:18

Je n'ai jamais utilisé de Prototype et je ne suis pas sûr de l'utilité que je serai. Mais j'ai jeté un coup d'oeil aux documents et je n'ai vu aucun support pour la méthode et les paramètres.

essayez donc:

new Ajax.Request(REQUEST_ADDRESS+"?stationString="+station_id, {
    onSuccess: displayMetar,
    onFailure: function() {
        $("errors").update("an error occurred");
    }
});

J'ai aussi remarqué que la chaîne de station dans votre exemple devrait être entre guillemets en supposant qu'il ne s'agit pas d'une variable.

0
répondu Adam 2012-12-11 06:29:16