AngularJS exécute une requête D'OPTIONS HTTP pour une ressource d'origine croisée

J'essaie de configurer AngularJS pour communiquer avec une ressource de cross-origin où l'hôte qui fournit mes fichiers de template est sur un domaine différent et donc la requête XHR que réalise angular doit être de cross-domain. J'ai ajouté l'en-tête CORS approprié à mon serveur pour la requête HTTP pour que cela fonctionne, mais cela ne semble pas fonctionner. Le problème est que lorsque J'inspecte les requêtes HTTP dans mon navigateur (chrome), la requête envoyée au fichier asset est une requête D'OPTIONS. (il devrait être d'une requête GET).

Je ne sais pas s'il s'agit d'un bug dans AngularJS ou si je dois configurer quelque chose. D'après ce que j'ai compris, XHR wrapper ne peut pas faire une requête HTTP OPTIONS, donc il semble que le navigateur essaye de comprendre si est "autorisé" à télécharger l'actif en premier avant d'effectuer la requête GET. Si c'est le cas, est-ce que je dois définir l'en-tête CORS (Access-Control-Allow-Origin: http://asset.hôte.. .) avec le l'hôte de l'atout aussi?

249
demandé sur matsko 2012-08-24 19:02:49

12 réponses

OPTIONS request ne sont en aucun cas un bug AngularJS, c'est ainsi que la norme Cross-Origin Resource Sharing oblige les navigateurs à se comporter. Se référer à ce document: https://developer.mozilla.org/en-US/docs/HTTP_access_control , où dans la section "Vue D'ensemble" il est dit:

Le Cross-Origin Resource sharing ouvrages de référence par l'ajout de nouveaux HTTP les en-têtes de permettre aux serveurs de décrire l'ensemble des origines qui sont autorisés à lire cette information à l'aide d'un navigateur web. Outre, pour les méthodes de requête HTTP qui peuvent causer des effets secondaires sur les données de l'utilisateur (dans particulier; pour les méthodes HTTP autres que GET, ou pour L'utilisation POST avec certains types de MIME). La spécification exige que les navigateurs "prévisualiser" la requête, en sollicitant les méthodes prises en charge par le serveur avec un en-tête de requête D'OPTIONS HTTP, puis, après "approbation" de le serveur, en envoyant la requête actuelle avec la requête HTTP actuelle méthode. Les serveurs peuvent informer également les clients si"" (y compris les Cookies et les données D'authentification HTTP) doivent être envoyés avec demande.

il est très difficile de fournir une solution générique qui fonctionnerait pour tous les serveurs WWW car la configuration variera en fonction du serveur lui-même et des verbes HTTP que vous avez l'intention de prendre en charge. Je vous encourage à vous remettre de cet excellent article ( http://www.html5rocks.com/en/tutorials/cors / ) qui a beaucoup plus détails sur les en-têtes exacts qui doivent être envoyés par un serveur.

216
répondu pkozlowski.opensource 2016-08-23 15:45:54

Pour L'Angle 1.2.0rc1 + vous devez ajouter une resourceUrlWhitelist.

1.2: version de sortie ils ont ajouté une fonction escapeForRegexp pour que vous n'ayez plus à échapper aux chaînes. Vous pouvez juste ajouter l'url directement

'http://sub*.assets.example.com/**' 

assurez-vous d'ajouter ** pour les sous-dossiers. Voici un jsbin de travail pour 1.2: http://jsbin.com/olavok/145/edit


1.2.0 rc: si vous êtes toujours sur une version rc, L'angle 1.2.La solution ressemble à:

.config(['$sceDelegateProvider', function($sceDelegateProvider) {
     $sceDelegateProvider.resourceUrlWhitelist(['self', /^https?:\/\/(cdn\.)?yourdomain.com/]);
 }])

voici un exemple de jsbin où il fonctionne pour 1.2.1: http://jsbin.com/olavok/144/edit


pré 1.2: pour les versions plus anciennes (réf http://better-inter.net/enabling-cors-in-angular-js / ) vous devez ajouter le suivant 2 lignes à votre configuration:

$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];

voici un exemple de jsbin où il fonctionne pour les versions pré 1.2: http://jsbin.com/olavok/11/edit

65
répondu JStark 2014-03-05 17:23:22

NOTE: pas sûr que cela fonctionne avec la dernière version D'Angular.

ORIGINAL:

il est également possible de passer outre à la requête D'OPTIONS (a été seulement testé dans Chrome):

app.config(['$httpProvider', function ($httpProvider) {
  //Reset headers to avoid OPTIONS request (aka preflight)
  $httpProvider.defaults.headers.common = {};
  $httpProvider.defaults.headers.post = {};
  $httpProvider.defaults.headers.put = {};
  $httpProvider.defaults.headers.patch = {};
}]);
58
répondu user2899845 2016-04-20 22:35:30

votre service doit répondre à une demande OPTIONS avec des en-têtes comme ceux-ci:

Access-Control-Allow-Origin: [the same origin from the request]
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: [the same ACCESS-CONTROL-REQUEST-HEADERS from request]

voici un bon doc: http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server

33
répondu user2304582 2014-08-25 13:25:09

le même document dit

Contrairement aux requêtes simples (discutées ci-dessus), les requêtes "préflighted" envoient d'abord un en-tête de requête D'OPTIONS HTTP à la ressource sur l'autre domaine, afin de déterminer si la requête actuelle est sûre à envoyer. Les requêtes intersites sont préfixées comme ceci puisqu'elles peuvent avoir des implications pour les données des utilisateurs. En particulier, une demande est préfixée si:

il utilise des méthodes autres que GET ou POST. En outre, si POST est utilisé pour envoyer des données de requête avec un type de contenu autre que application/x-www-form-urlencoded, multipart/form-data, ou text/plain, par exemple si la requête POST envoie une charge utile XML au serveur en utilisant application/xml ou text/xml, alors la requête est pré-allumée.

définit des en-têtes personnalisés dans la requête (par exemple, la requête utilise un en-tête tel que X-PINGOTHER)

lorsque la demande originale est Get sans en-tête personnalisé, le le navigateur ne devrait pas faire de demande D'Options ce qu'il fait maintenant. Le problème est qu'il génère un en-tête X-Requested-qui force la requête D'Options. Voir https://github.com/angular/angular.js/pull/1454 sur la façon de supprimer cet en-tête

20
répondu Grum Ketema 2014-04-29 18:59:07

Cela a réglé mon problème:

$http.defaults.headers.post["Content-Type"] = "text/plain";
10
répondu Cem Arguvanlı 2016-02-25 13:06:28

si vous utilisez un serveur nodeJS, vous pouvez utiliser cette bibliothèque, il a fonctionné très bien pour moi https://github.com/expressjs/cors

var express = require('express')
  , cors = require('cors')
  , app = express();

app.use(cors());

et après vous pouvez faire un npm update .

10
répondu Zakaria.dem 2016-10-16 22:29:49

Voici comment j'ai réglé ce problème ASP.NET

  • tout d'abord, vous devez ajouter le paquet nuget Microsoft.AspNet.WebApi.La scro

  • puis modifier le fichier App_Start\WebApiConfig.cs

    public static class WebApiConfig    
    {
       public static void Register(HttpConfiguration config)
       {
          config.EnableCors();
    
          ...
       }    
    }
    
  • ajouter cet attribut sur votre classe de contrôleur

    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class MyController : ApiController
    {  
        [AcceptVerbs("POST")]
        public IHttpActionResult Post([FromBody]YourDataType data)
        {
             ...
             return Ok(result);
        }
    }
    
  • j'ai été capable d'envoyer json à l'action par cette voie

    $http({
            method: 'POST',
            data: JSON.stringify(data),
            url: 'actionurl',
            headers: {
                'Content-Type': 'application/json; charset=UTF-8'
            }
        }).then(...)
    

référence: permettant les demandes D'origine croisée dans ASP.NET Web API 2

4
répondu asfez 2016-06-23 14:45:31

D'une façon ou d'une autre je l'ai corrigé en changeant

Access-Control-Allow-Les En-Têtes "À L'Origine, X-Requested-With, Content-Type, D'Accepter, De L'Autorisation"

à

Access-Control-Allow-Les En-Têtes "À L'Origine, Le Type De Contenu, D'Accepter, De L'Autorisation"

1
répondu Ved Prakash 2016-03-14 15:21:49

parfaitement décrit dans le commentaire de pkozlowski. J'ai eu une solution de travail avec AngularJS 1.2.6 et ASP.NET Api Web mais quand J'ai mis à jour AngularJS à 1.3.3, les requêtes ont échoué.

  • la Solution pour le serveur D'Api Web était d'ajouter le traitement des requêtes D'OPTIONS au début de la méthode de configuration (plus d'informations dans ce billet de blog ):

    app.Use(async (context, next) =>
    {
        IOwinRequest req = context.Request;
        IOwinResponse res = context.Response;
        if (req.Path.StartsWithSegments(new PathString("/Token")))
        {
            var origin = req.Headers.Get("Origin");
            if (!string.IsNullOrEmpty(origin))
            {
                res.Headers.Set("Access-Control-Allow-Origin", origin);
            }
            if (req.Method == "OPTIONS")
            {
                res.StatusCode = 200;
                res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Methods", "GET", "POST");
                res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Headers", "authorization", "content-type");
                return;
            }
        }
        await next();
    });
    
0
répondu Jiří Kavulák 2015-02-27 09:11:34

si vous utilisez Jersey for REST API vous pouvez faire comme ci-dessous""

vous n'avez pas à changer votre implémentation webservices.

je vais expliquer Pour Jersey 2.x

1) Ajouter D'abord un filtre comme indiqué ci-dessous

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

public class CorsResponseFilter implements ContainerResponseFilter {

@Override
public void filter(ContainerRequestContext requestContext,   ContainerResponseContext responseContext)
    throws IOException {
        responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
        responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");

  }
}

2) puis sur le web.xml, dans la déclaration de jersey servlet ajouter le suivant

    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
    </init-param>
0
répondu nondescript 2015-05-26 06:29:25

j'ai renoncé à essayer de résoudre ce problème.

My IIS web.config avait le " Access-Control-Allow-Methods " pertinent, j'ai expérimenté l'ajout de paramètres de configuration à mon code angulaire, mais après avoir brûlé quelques heures à essayer de faire appeler Chrome un service Web JSON cross-domain, j'ai abandonné misérablement.

à la fin, j'ai ajouté un muet ASP.Net handler webpage, got que pour appeler mon service JSON web, et de retourner les résultats. Il était en haut et en cours d'exécution dans Les 2 minutes.

voici le code que j'ai utilisé:

public class LoadJSONData : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";

        string URL = "......";

        using (var client = new HttpClient())
        {
            // New code:
            client.BaseAddress = new Uri(URL);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Add("Authorization", "Basic AUTHORIZATION_STRING");

            HttpResponseMessage response = client.GetAsync(URL).Result;
            if (response.IsSuccessStatusCode)
            {
                var content = response.Content.ReadAsStringAsync().Result;
                context.Response.Write("Success: " + content);
            }
            else
            {
                context.Response.Write(response.StatusCode + " : Message - " + response.ReasonPhrase);
            }
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

et dans mon régulateur angulaire...

$http.get("/Handlers/LoadJSONData.ashx")
   .success(function (data) {
      ....
   });

je suis sûr qu'il y a une façon plus simple/plus générique de le faire, mais la vie est trop courte...

cela a fonctionné pour moi, et je peux continuer à faire du travail normal maintenant !!

0
répondu Mike Gledhill 2015-11-11 12:42:33