Jak włączyć CORS w AngularJs

147

Stworzyłem demo przy użyciu JavaScript dla interfejsu API wyszukiwania zdjęć Flickr. Teraz konwertuję go na AngularJs. Przeszukałem internet i znalazłem poniżej konfigurację.

Konfiguracja:

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

Usługa:

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'}
         });
     }
});

Kontroler:

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

Ale nadal mam ten sam błąd. Oto kilka linków, które wypróbowałem:

XMLHttpRequest nie może załadować adresu URL. Pochodzenie niedozwolone przez Access-Control-Allow-Origin

http://goo.gl/JuS5B1

ankitr
źródło
1
Musisz zażądać danych od swojego serwera proxy, nadal żądasz ich bezpośrednio od flickr.
Quentin
@quentin Dzięki za szybką odpowiedź. Czy możesz mi dać demo.
ankitr
1
Wystarczy zmienić adres URL z flickr.com na adres URL swojego serwera proxy
Quentin
1
Ale jak mam zadzwonić do flickr? jak potrzebuję zdjęć z flickr.
ankitr
2
Klient dzwoni do serwera proxy. Serwer proxy wywołuje flickr. To właśnie oznacza proxy. (Twój kod proxy… nie jest serwerem proxy, jest to serwer WWW do obsługi JSON i JSONP z plików statycznych).
Quentin

Odpowiedzi:

193

Ty nie. Serwer, do którego wysyłasz żądanie, musi zaimplementować mechanizm CORS, aby przyznać dostęp JavaScript do Twojej witryny. Twój JavaScript nie może przyznać sobie uprawnień dostępu do innej witryny.

Quentin
źródło
1
Zamiast tego wysyłaj żądania do Flickr ze swojego serwera.
Quentin
Nie używam serwera, ale mogę używać node.js. Czy możesz mi pokazać drogę z tym?
ankitr
1
Nie w miejscu dostępnym w komentarzu. To dość obszerny zestaw tematów.
Quentin,
Dlaczego jest to, że mogę dostać odpowiedź z https://www.google.comwykorzystaniem aplikacji takich jak listonosz, ale przy próbie GETz https://www.google.comużyciem wywołanie AJAX pojawia się błąd CORS? Czy nie ma sposobu, aby wywołanie AJAX zachowywało się podobnie do wywołania z programu POSTMAN?
AjaxLeung
5
@AlexLeung - Postman to zainstalowana aplikacja. Gdyby Twoja witryna mogła zażądać danych od Google i odczytać je, mogłaby zażądać mojej strony skrzynki odbiorczej Gmaila i przeczytać całą moją pocztę e-mail. To byłoby straszne.
Quentin
64

Miałem podobny problem i jak dla mnie sprowadzało się to do dodania następujących nagłówków HTTP w odpowiedzi strony odbierającej :

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

Możesz wolisz nie używać *na końcu, a jedynie nazwę domeny hosta wysyłającego dane. Lubić*.example.com

Ale jest to możliwe tylko wtedy, gdy masz dostęp do konfiguracji serwera.

Erwin
źródło
2
Jestem nowy w AngularJs. Czy możesz mi powiedzieć, gdzie to wdrożyć?
ankitr
17
@Ankit Musisz dodać te nagłówki na serwerze , a nie w AngularJS.
Felipe
2
@techcraver - Nie potrzebujesz operacyjnego dostępu do konfiguracji serwera - wystarczy przekazać nagłówki z poziomu skryptu. Jeśli masz zaplecze PHP, byłoby toheader('Access-Control-Allow-Origin: *');
davidkonrad,
@davidkonrad: Całą aplikację stworzyłem w wersji Angular v4. Czy możesz powiedzieć, gdzie mam dołączyć ten nagłówek: /
Pygirl
@Pygirl, wydaje mi się, że skierowałeś klienta w stronę kątową? Musisz dodać nagłówki po stronie serwera odpowiedzi, jak i gdzie zależą od technologii. Jeśli jest to skrypt PHP, który wywołujesz z kątowego Http.get()lub podobnego, dodaj header('Access-Control-Allow-Origin: *')jako pierwsze wyjście w wywołanym skrypcie PHP (tj. Zanim
wypiszesz
9

Spróbuj skorzystać z usługi zasobów, aby wykorzystać 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' });
});

Szablon:

<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
źródło
4

Ten problem występuje z powodu zasady modelu zabezpieczeń aplikacji sieci Web, która ma takie same zasady pochodzenia. Zgodnie z tą zasadą przeglądarka internetowa zezwala skryptom zawartym na pierwszej stronie internetowej na dostęp do danych na drugiej stronie internetowej, ale tylko wtedy, gdy obie strony mają to samo źródło. Oznacza to, że żądający musi dokładnie dopasować hosta, protokół i port żądającej witryny.

Mamy wiele możliwości rozwiązania problemu z nagłówkiem CORS.

  1. Korzystanie z serwera proxy - w tym rozwiązaniu uruchomimy serwer proxy w taki sposób, że gdy żądanie przechodzi przez serwer proxy, będzie wyglądać, jakby pochodziło z tego samego źródła. Jeśli używasz nodeJS można użyć Cors-gdzie zrobić rzeczy proxy. https://www.npmjs.com/package/cors-anywhere .

    Przykład : -

    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 to metoda wysyłania danych JSON bez obawy o problemy międzydomenowe, która nie wykorzystuje obiektu XMLHttpRequest, <script>zamiast tego używa tagu. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Server Side - po stronie serwera musimy włączyć żądań między pochodzenia. Najpierw otrzymamy żądania Preflighted (OPCJE) i musimy zezwolić na żądanie o kodzie stanu 200 (ok).

    Żądania z inspekcją wstępną najpierw wysyłają nagłówek żądania HTTP OPTIONS do zasobu w innej domenie, aby określić, czy rzeczywiste żądanie można bezpiecznie wysłać. Żądania między witrynami są wstępnie analizowane w ten sposób, ponieważ mogą mieć wpływ na dane użytkownika. W szczególności żądanie jest wstępnie sprawdzane, jeśli używa metod innych niż GET lub POST. Ponadto, jeśli POST jest używany do wysyłania danych żądania z typem zawartości innym niż application / x-www-form-urlencoded, multipart / form-data lub text / plain, np. Jeśli żądanie POST wysyła ładunek XML do serwera przy użyciu application / xml lub text / xml, a następnie żądanie jest wstępnie sprawdzane. Ustawia niestandardowe nagłówki w żądaniu (np. Żądanie używa nagłówka, takiego jak X-PINGOTHER)

    Jeśli używasz sprężyny, wystarczy dodać poniższy kod, aby rozwiązać problem. Tutaj wyłączyłem token csrf, który nie ma znaczenia, włącz / wyłącz zgodnie z twoimi wymaganiami.

    @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("*");
                }
            };
        }
    }

    Jeśli korzystasz z zabezpieczenia sprężynowego, użyj poniższego kodu wraz z powyższym kodem.

    @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
źródło
2

Napotkałem podobny problem, jak ten, problem dotyczył zaplecza. Używałem serwera węzłowego (Express). Otrzymałem żądanie od frontendu (kątowe), jak pokazano poniżej

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

Ale dał następujący błądBłąd

To jest kod zaplecza napisany przy użyciu express bez nagłówków

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

Po dodaniu nagłówka do metody problem został rozwiązany

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

Możesz uzyskać więcej informacji na temat włączania mechanizmu CORS w Node JS

Janith Udara
źródło
1

Odpowiedziałem przeze mnie.

CORS kątowy js + restEasy on POST

W końcu doszedłem do tego obejścia: Powodem, dla którego zadziałało z IE, jest to, że IE wysyła bezpośrednio POST zamiast najpierw prośby o pozwolenie. Ale nadal nie wiem, dlaczego filtr nie był w stanie zarządzać żądaniem OPTIONS i domyślnie wysyła nagłówki, które nie są opisane w filtrze (wydaje się, że zastąpienie dla tego jedynego przypadku ... może reszta Łatwa rzecz ... .)

Więc utworzyłem ścieżkę OPTIONS w mojej usłudze resztowej, która przepisuje odpowiedź i zawiera nagłówki w odpowiedzi za pomocą nagłówka odpowiedzi

Wciąż szukam prostego sposobu na zrobienie tego, jeśli ktoś wcześniej miał z tym do czynienia.

J.Doe
źródło
1

Apache / HTTPD zwykle występuje w większości przedsiębiorstw lub jeśli używasz Centos / etc w domu. Więc jeśli masz to w pobliżu, możesz bardzo łatwo zrobić proxy, aby dodać niezbędne nagłówki CORS.

Mam tutaj wpis na blogu na ten temat , ponieważ ostatnio cierpiałem z tym kilka razy. Ale ważne jest po prostu dodanie tego do pliku /etc/httpd/conf/httpd.conf i upewnienie się, że już wykonujesz „Listen 80”:

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

Gwarantuje to, że wszystkie żądania do adresów URL z twojego-server-ip: 80 / SomePath kierują do http: // target-ip: 8080 / SomePath (API bez obsługi CORS) i wracają z poprawnym Access-Control-Allow- Nagłówek Origin, aby umożliwić im pracę z Twoją aplikacją internetową.

Oczywiście możesz zmienić porty i kierować reklamy na cały serwer zamiast na SomePath, jeśli chcesz.

John Humphreys - w00te
źródło
1

W tej odpowiedzi przedstawiono dwa sposoby obejścia interfejsów API, które nie obsługują mechanizmu CORS:

  • Użyj serwera proxy CORS
  • Użyj formatu JSONP, jeśli obsługuje go interfejs API

Jednym obejściem jest użycie 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>

Więcej informacji znajdziesz w


Użyj JSONP, jeśli obsługuje to API:

 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;
 }) 

DEMO na PLNKR

Więcej informacji znajdziesz w

georgeawg
źródło
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
źródło
„A także dodaj następujący kod do pliku WebApiConfig” - pytanie dotyczy wysłania żądania do Flickr. Ich serwery nie są pod kontrolą OP. Flickr prawdopodobnie również nie używa ASP.NET.
Quentin
0

możemy włączyć CORS w interfejsie użytkownika za pomocą modułu ngResourse. Ale co najważniejsze, powinniśmy mieć ten fragment kodu podczas wysyłania żądania Ajax do kontrolera,

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

Ponadto należy dodać ngResourse CDN w części skryptu i dodać jako zależność w module aplikacji.

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

Następnie użyj „ngResourse” w sekcji zależności modułu aplikacji

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

Alok Ranjan
źródło