Como habilitar o CORS em AngularJs

147

Eu criei uma demonstração usando JavaScript para a API de pesquisa de fotos do Flickr. Agora estou convertendo para os AngularJs. Eu pesquisei na internet e encontrei abaixo a configuração.

Configuração:

myApp.config(function($httpProvider) {
  $httpProvider.defaults.useXDomain = true;
  delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

Serviço:

myApp.service('dataService', function($http) {
    delete $http.defaults.headers.common['X-Requested-With'];
    this.flickrPhotoSearch = function() {
        return $http({
            method: 'GET',
            url: 'http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=3f807259749363aaa29c76012fa93945&tags=india&format=json&callback=?',
            dataType: 'jsonp',
            headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
         });
     }
});

Controlador:

myApp.controller('flickrController', function($scope, dataService) {
        $scope.data = null;
        dataService.flickrPhotoSearch().then(function(dataResponse) {
            $scope.data = dataResponse;
            console.log($scope.data);
        });
    });

Mas ainda assim eu recebi o mesmo erro. Aqui estão alguns links que eu tentei:

XMLHttpRequest não pode carregar o URL. Origem não permitida pelo Access-Control-Allow-Origin

http://goo.gl/JuS5B1

ankitr
fonte
1
Você precisa solicitar os dados do seu proxy, você ainda está solicitando diretamente do flickr.
Quentin
@ Quentin Obrigado pela resposta rápida. Você pode me dar uma demonstração?
Ankitr 29/05
1
Você acabou de alterar o URL do flickr.com para o URL do seu proxy
Quentin
1
Mas como vou ligar para o flickr? como eu preciso das imagens do flickr.
Ankitr
2
O cliente chama o proxy. O proxy chama flickr. É isso que proxy significa. (Seu código de proxy ... não é um proxy, é um servidor da web para servir JSON e JSONP a partir de arquivos estáticos).
Quentin

Respostas:

193

Você não O servidor para o qual você está solicitando deve implementar o CORS para conceder JavaScript a partir do acesso ao seu site. Seu JavaScript não pode conceder permissão para acessar outro site.

Quentin
fonte
1
Faça os pedidos para o Flickr do seu servidor.
Quentin
Não estou usando um servidor, mas posso usar o node.js. Você pode me mostrar o caminho com isso?
Ankitr 23/05
1
Não está no espaço disponível em um comentário. É um grande conjunto de tópicos.
Quentin
Por que é que eu posso obter uma resposta da https://www.google.comusando um aplicativo como o carteiro, mas quando eu tento GETde https://www.google.comusar uma chamada de AJAX eu recebo o erro CORS? Não há como eu fazer com que a chamada AJAX se comporte de maneira semelhante à da POSTMAN?
AjaxLeung
5
@AlexLeung - Postman é um aplicativo instalado. Se o seu site puder fazer meu navegador solicitar dados do Google e lê-los, ele poderá solicitar minha página da Caixa de entrada do GMail e ler todos os meus e-mails. Isso seria terrível.
Quentin
64

Eu tive um problema semelhante e, para mim, resumiu-se à adição dos seguintes cabeçalhos HTTP na resposta do recebimento :

Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *

Você pode preferir não usar o *no final, mas apenas o nome de domínio do host que está enviando os dados. Gostar*.example.com

Mas isso só é possível quando você tem acesso à configuração do servidor.

Erwin
fonte
2
Eu sou novo no AngularJs. Por favor, você pode me dizer onde implementar isso?
Ankitr 26/05
17
@ Ankit Você precisa adicionar esses cabeçalhos no servidor , não no AngularJS.
Felipe
2
@techcraver - Você não precisa de acesso operacional à configuração do servidor - basta passar os cabeçalhos de dentro do seu script. Se você tem um PHP backend seriaheader('Access-Control-Allow-Origin: *');
davidkonrad
@ Davidkonrad: Eu criei o aplicativo inteiro na v4 angular. Você pode dizer onde eu tenho que incluir estes cabeçalhos: /
Pygirl
@ Pygirl, acredito que você fez o lado do cliente em angular? Você precisa adicionar cabeçalhos ao servidor de resposta, como e onde dependem da tecnologia. Se for um script PHP que você chama de um angular Http.get()ou similar, adicione header('Access-Control-Allow-Origin: *')como a primeira saída no script PHP chamado (ou seja, antes de você
gerar
9

Tente usar o serviço de recurso para consumir o flickr jsonp:

var MyApp = angular.module('MyApp', ['ng', 'ngResource']);

MyApp.factory('flickrPhotos', function ($resource) {
    return $resource('http://api.flickr.com/services/feeds/photos_public.gne', { format: 'json', jsoncallback: 'JSON_CALLBACK' }, { 'load': { 'method': 'JSONP' } });
});

MyApp.directive('masonry', function ($parse) {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.masonry({ itemSelector: '.masonry-item', columnWidth: $parse(attrs.masonry)(scope) });
        }
    };        
});

MyApp.directive('masonryItem', function () {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.imagesLoaded(function () {
               elem.parents('.masonry').masonry('reload');
            });
        }
    };        
});

MyApp.controller('MasonryCtrl', function ($scope, flickrPhotos) {
    $scope.photos = flickrPhotos.load({ tags: 'dogs' });
});

Modelo:

<div class="masonry: 240;" ng-controller="MasonryCtrl">
    <div class="masonry-item" ng-repeat="item in photos.items">
        <img ng-src="{{ item.media.m }}" />
    </div>
</div>
Ali Habibzadeh
fonte
4

Esse problema ocorre devido à diretiva de modelo de segurança de aplicativos da web que é a mesma diretiva de origem De acordo com a política, um navegador da web permite que os scripts contidos em uma primeira página da Web acessem dados em uma segunda página da Web, mas apenas se as duas páginas da Web tiverem a mesma origem. Isso significa que o solicitante deve corresponder ao host, protocolo e porta exatos do site solicitante.

Temos várias opções para superar esse problema de cabeçalho do CORS.

  1. Usando Proxy - Nesta solução, executaremos um proxy de forma que, quando a solicitação for feita, ele parecerá ter a mesma origem. Se você estiver usando o nodeJS, poderá usar cors-qualquer lugar para executar as tarefas de proxy. https://www.npmjs.com/package/cors-anywhere .

    Exemplo : -

    var host = process.env.HOST || '0.0.0.0';
    var port = process.env.PORT || 8080;
    var cors_proxy = require('cors-anywhere');
    cors_proxy.createServer({
        originWhitelist: [], // Allow all origins
        requireHeader: ['origin', 'x-requested-with'],
        removeHeaders: ['cookie', 'cookie2']
    }).listen(port, host, function() {
        console.log('Running CORS Anywhere on ' + host + ':' + port);
    });
  2. JSONP - JSONP é um método para enviar dados JSON sem se preocupar com problemas entre domínios. Ele não usa o objeto XMLHttpRequest. Ele usa a <script>tag. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Lado do servidor - No lado do servidor, precisamos ativar solicitações de origem cruzada. Primeiro, obteremos as solicitações comprovadas (OPTIONS) e precisamos permitir a solicitação com o código de status 200 (ok).

    Solicitações comprovadas primeiro enviam um cabeçalho de solicitação HTTP OPTIONS para o recurso no outro domínio, a fim de determinar se a solicitação real é segura para enviar. As solicitações entre sites são comprovadas dessa maneira, pois podem ter implicações nos dados do usuário. Em particular, uma solicitação é comprovada se usar métodos diferentes de GET ou POST. Além disso, se o POST for usado para enviar dados da solicitação com um Tipo de Conteúdo diferente de application / x-www-form-urlencoded, multipart / form-data ou text / plain, por exemplo, se a solicitação POST enviar uma carga XML para o servidor usando application / xml ou text / xml, a solicitação é comprovada. Ele define cabeçalhos personalizados na solicitação (por exemplo, a solicitação usa um cabeçalho como X-PINGOTHER)

    Se você estiver usando a mola, basta adicionar o código abaixo para resolver o problema. Aqui desabilitei o token csrf que não importa, habilite / desabilite de acordo com sua necessidade.

    @SpringBootApplication
    public class SupplierServicesApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SupplierServicesApplication.class, args);
        }
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**").allowedOrigins("*");
                }
            };
        }
    }

    Se você estiver usando a segurança de mola, use o código abaixo, juntamente com o código acima.

    @Configuration
    @EnableWebSecurity
    public class SupplierSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().antMatchers("/**").authenticated().and()
                    .httpBasic();
        }
    
    }
Niru
fonte
2

Eu encontrei um problema semelhante como este, o problema estava com o back-end. Eu estava usando o servidor do nó (Express). Recebi uma solicitação de obtenção do front-end (angular), como mostrado abaixo

   onGetUser(){
        return this.http.get("http://localhost:3000/user").pipe(map(
            (response:Response)=>{
                const user =response.json();
                return user;
            }
        )) 
    }

Mas deu o seguinte erroO erro

Este é o código de back-end escrito usando express sem os cabeçalhos

app.get('/user',async(req,res)=>{
     const user=await getuser();
     res.send(user);
 })

Após adicionar um cabeçalho ao método, o problema foi resolvido

app.get('/user',async(req,res)=>{
    res.header("Access-Control-Allow-Origin", "*");
    const user=await getuser();
    res.send(user);
})

Você pode obter mais detalhes sobre a ativação do CORS no nó JS

Janith Udara
fonte
1

Respondeu por mim mesmo.

CORS angular js + restEasy no POST

Bem, finalmente cheguei a esta solução alternativa: o motivo pelo qual ele trabalhou com o IE é porque o IE envia diretamente um POST em vez de primeiro um pedido de comprovação para pedir permissão. Mas ainda não sei por que o filtro não conseguiu gerenciar uma solicitação OPTIONS e envia por cabeçalhos padrão que não são descritos no filtro (parece uma substituição para esse único caso ... talvez uma coisa restEasy .. .)

Então, criei um caminho OPTIONS no meu serviço de descanso que reescreve a resposta e inclui os cabeçalhos na resposta usando o cabeçalho de resposta

Ainda estou procurando uma maneira limpa de fazer isso, se alguém já enfrentou isso antes.

J.Doe
fonte
1

O Apache / HTTPD tende a existir na maioria das empresas ou se você estiver usando o Centos / etc em casa. Portanto, se você tiver isso por perto, poderá fazer um proxy com muita facilidade para adicionar os cabeçalhos CORS necessários.

Eu tenho um post sobre isso aqui, pois sofri algumas vezes recentemente. Mas o importante é apenas adicionar isso ao seu arquivo /etc/httpd/conf/httpd.conf e garantir que você já esteja executando o "Listen 80":

<VirtualHost *:80>
    <LocationMatch "/SomePath">
       ProxyPass http://target-ip:8080/SomePath
       Header add "Access-Control-Allow-Origin" "*"
    </LocationMatch>
</VirtualHost>

Isso garante que todas as solicitações de URLs sob seu servidor-ip: 80 / SomePath sejam roteadas para http: // target-ip: 8080 / SomePath (a API sem suporte ao CORS) e que elas retornem com o acesso correto de controle de permissão- Cabeçalho de origem para permitir que eles funcionem com seu aplicativo da web.

É claro que você pode alterar as portas e direcionar todo o servidor, em vez de SomePath, se desejar.

John Humphreys - w00te
fonte
1

Esta resposta descreve duas maneiras de solucionar as APIs que não suportam o CORS:

  • Use um proxy CORS
  • Use JSONP se a API o suportar

Uma solução alternativa é usar um CORS PROXY:

angular.module("app",[])
.run(function($rootScope,$http) { 
     var proxy = "//cors-anywhere.herokuapp.com";
     var url = "http://api.ipify.org/?format=json";
     $http.get(proxy +'/'+ url)
       .then(function(response) {
         $rootScope.response = response.data;
     }).catch(function(response) {
         $rootScope.response = 'ERROR: ' + response.status;
     })     
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
   Response = {{response}}
</body>

Para mais informações, veja


Use JSONP se a API suportar:

 var url = "//api.ipify.org/";
 var trust = $sce.trustAsResourceUrl(url);
 $http.jsonp(trust,{params: {format:'jsonp'}})
   .then(function(response) {
     console.log(response);
     $scope.response = response.data;
 }).catch(function(response) {
     console.log(response);
     $scope.response = 'ERROR: ' + response.status;
 }) 

A DEMO em PLNKR

Para mais informações, veja

georgeawg
fonte
0
        var result=[];
        var app = angular.module('app', []);
        app.controller('myCtrl', function ($scope, $http) {
             var url="";// your request url    
             var request={};// your request parameters
             var headers = {
             // 'Authorization': 'Basic ' + btoa(username + ":" + password),
            'Access-Control-Allow-Origin': true,
            'Content-Type': 'application/json; charset=utf-8',
            "X-Requested-With": "XMLHttpRequest"
              }
             $http.post(url, request, {
                        headers
                 })
                 .then(function Success(response) {
                      result.push(response.data);             
                      $scope.Data = result;              
                 }, 
                  function Error(response) {
                      result.push(response.data);
                       $scope.Data = result;
                    console.log(response.statusText + " " + response.status)
               }); 
     });

And also add following code in your WebApiConfig file            
        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);
shiva samalla
fonte
"E também adicione o seguinte código no seu arquivo WebApiConfig" - A questão é sobre fazer uma solicitação ao Flickr. Seus servidores não estão sob o controle do OP. O Flickr provavelmente também não está usando o ASP.NET.
Quentin
0

podemos ativar o CORS no front-end usando o módulo ngResourse. Mas o mais importante, devemos ter esse pedaço de código ao fazer a solicitação ajax no controlador,

$scope.weatherAPI = $resource(YOUR API,
     {callback: "JSON_CALLBACK"}, {get: {method: 'JSONP'}});
 $scope.weatherResult = $scope.weatherAPI.get(YOUR REQUEST DATA, if any);

Além disso, você deve adicionar o ngResourse CDN na parte do script e adicionar como uma dependência no módulo do aplicativo.

<script src="https://code.angularjs.org/1.2.16/angular-resource.js"></script>

Em seguida, use "ngResourse" na seção de dependência do módulo de aplicativo

var routerApp = angular.module("routerApp", ["ui.router", 'ngResource']);

Alok Ranjan
fonte