web-dev-qa-db-fra.com

jQuery.getJSON - Problème Access-Control-Allow-Origin

J'utilise la fonction $.getJSON() de jQuery pour renvoyer un court ensemble de données JSON.

J'ai les données JSON sur une URL telle que example.com. Je ne m'en rendais pas compte, mais comme j'accédais à cette même URL, les données JSON ne pouvaient pas être chargées. J'ai suivi la console et j'ai constaté que XMLHttpRequest ne pouvait pas se charger en raison de Access-Control-Allow-Origin.

Maintenant, j'ai lu, beaucoup de sites qui ont juste dit d'utiliser $.getJSON() et ce serait le travail, mais évidemment cela n'a pas fonctionné. Y a-t-il quelque chose que je devrais changer dans les en-têtes ou dans la fonction?

L'aide est grandement appréciée.

37
Mike

C'est simple, utilisez la fonction $.getJSON() et dans votre URL, incluez simplement

rappel =?

comme paramètre. Cela convertira l'appel en JSONP, ce qui est nécessaire pour effectuer des appels interdomaines. Plus d'informations: http://api.jquery.com/jQuery.getJSON/

73
Hammad Tariq

Vous voudrez peut-être plutôt utiliser JSON-P (voir ci-dessous). D'abord une explication rapide.

L'en-tête que vous avez mentionné provient de la norme Cross Origin Resource Sharing . Attention, c'est non pris en charge par certains navigateurs que les gens utilisent réellement, et sur d'autres navigateurs (Microsoft, soupir) cela nécessite l'utilisation d'un objet spécial (XDomainRequest) plutôt que la norme XMLHttpRequest que jQuery utilise. Il requiert également que vous modifiiez les ressources côté serveur pour autoriser explicitement l'autre Origin (www.xxxx.com).

Pour obtenir les données JSON que vous demandez, vous avez essentiellement trois options:

  1. Si possible, vous pouvez être compatible au maximum en corrigeant l'emplacement des fichiers que vous chargez afin qu'ils aient la même origine que le document dans lequel vous les chargez. (Je suppose que vous devez les charger via Ajax, d'où le problème Même politique d'origine qui apparaît.)

  2. Utilisez JSON-P , qui n'est pas soumis à la SOP. jQuery a un support intégré pour cela dans son appel ajax (il suffit de définir dataType sur "jsonp" et jQuery fera tout le travail côté client). Cela nécessite des modifications côté serveur, mais pas très importantes; Fondamentalement, tout ce que vous avez qui génère la réponse JSON recherche simplement un paramètre de chaîne de requête appelé "rappel" et encapsule le JSON dans du code JavaScript qui appellerait cette fonction. Par exemple, si votre réponse JSON actuelle est:

    {"weather": "Dreary start but soon brightening into a fine summer day."}
    

    Votre script rechercherait le paramètre de chaîne de requête "rappel" (disons que la valeur du paramètre est "jsop123") et encapsule ce JSON dans la syntaxe d'un appel de fonction JavaScript:

    jsonp123({"weather": "Dreary start but soon brightening into a fine summer day."});
    

    C'est ça. JSON-P est très largement compatible (car il fonctionne via les balises JavaScript script). JSON-P est seulement pour GET, mais pas POST (encore une fois parce qu'il fonctionne via les balises script).

  3. Utilisez CORS (le mécanisme lié à l'en-tête que vous avez cité). Détails dans la spécification liée ci-dessus , mais fondamentalement:

    A. Le navigateur enverra à votre serveur un message de "contrôle en amont" en utilisant le verbe HTTP OPTIONS HTTP (méthode). Il contiendra les différents en-têtes qu'il enverra avec GET ou POST ainsi que les en-têtes "Origin", "Access-Control-Request-Method" (par exemple, GET ou POST), et "Access-Control-Request-Headers" (les en-têtes qu'il souhaite envoyer).

    B. Votre PHP décide, sur la base de ces informations, si la demande est correcte et, dans l’affirmative, répond par "Access-Control-Allow-Origin", "Access-Control-Allow-Methods" et les en-têtes "Access-Control-Allow-Headers" avec les valeurs autorisées. Vous n'envoyez aucun corps (page) avec cette réponse.

    C. Le navigateur examinera votre réponse et verra s'il est autorisé de vous envoyer le GET ou POST réel. Si c'est le cas, il enverra cette demande, toujours avec les en-têtes "Origin" et divers "Access-Control-Request-xyz".

    D. Votre PHP examine ces en-têtes encore pour vous assurer qu'ils sont toujours corrects, et si oui, répond à la demande.

    En pseudo - code (je n'ai pas fait beaucoup de PHP, donc je n'essaye pas de faire PHP syntaxe ici):

    // Find out what the request is asking for
    corsOrigin = get_request_header("Origin")
    corsMethod = get_request_header("Access-Control-Request-Method")
    corsHeaders = get_request_header("Access-Control-Request-Headers")
    if corsOrigin is null or "null" {
        // Requests from a `file://` path seem to come through without an
        // Origin or with "null" (literally) as the Origin.
        // In my case, for testing, I wanted to allow those and so I output
        // "*", but you may want to go another way.
        corsOrigin = "*"
    }
    
    // Decide whether to accept that request with those headers
    // If so:
    
    // Respond with headers saying what's allowed (here we're just echoing what they
    // asked for, except we may be using "*" [all] instead of the actual Origin for
    // the "Access-Control-Allow-Origin" one)
    set_response_header("Access-Control-Allow-Origin", corsOrigin)
    set_response_header("Access-Control-Allow-Methods", corsMethod)
    set_response_header("Access-Control-Allow-Headers", corsHeaders)
    if the HTTP request method is "OPTIONS" {
        // Done, no body in response to OPTIONS
        stop
    }
    // Process the GET or POST here; output the body of the response
    

    Soulignant à nouveau qu'il s'agit d'un pseudo-code.

38
T.J. Crowder