AngularJs'de CORS nasıl etkinleştirilir


148

Flickr fotoğraf arama API'si için JavaScript kullanarak bir demo oluşturdum. Şimdi onu AngularJ'lere dönüştürüyorum. İnternette aradım ve aşağıdaki konfigürasyonu buldum.

Yapılandırma:

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

Hizmet:

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

Denetleyici:

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

Ama yine de aynı hatayı aldım. İşte denediğim bazı bağlantılar:

XMLHttpRequest URL'yi yükleyemiyor. Menşe Access-Control-Allow-Origin tarafından izin verilmiyor

http://goo.gl/JuS5B1


1
Verileri proxy'nizden istemelisiniz, yine de doğrudan flickr'dan talep ediyorsunuz.
Quentin

@quentin Hızlı cevap için teşekkürler. Lütfen bana bir demo verir misin?
ankitr

1
URL'yi flickr.com'dan proxy'nizin URL'sine değiştirmeniz yeterlidir
Quentin

1
Ama flickr'ı nasıl arayacağım? flickr'dan gelen görüntülere ihtiyacım olduğu için.
ankitr

2
Müşteri vekili çağırır. Proxy, flickr'ı çağırır. Vekaletin anlamı budur. (Proxy kodunuz… bir proxy değil, statik dosyalardan JSON ve JSONP sunmak için bir web sunucusudur).
Quentin

Yanıtlar:


195

Yapmıyorsun. Talepte bulunduğunuz sunucu, web sitenize erişim izni vermek için CORS uygulamalıdır. JavaScript'iniz, kendisine başka bir web sitesine erişim izni veremez.


1
Bunun yerine sunucunuzdan Flickr'a istekte bulunun.
Quentin

Sunucu kullanmıyorum ama node.js kullanabilirim. Bununla bana yolu gösterebilir misin?
ankitr

1
Yorumda bulunan alanda değil. Oldukça büyük bir konu dizisi.
Quentin

Neden ben bir yanıt alabiliriz https://www.google.comPostacı gibi bir uygulama kullanarak, ama çalıştığımda GETgelen https://www.google.combir AJAX çağrısı kullanarak ben CORS hata alıyorum? AJAX aramasının POSTMAN'dan gelen aramaya benzer şekilde davranmasını sağlamamın bir yolu yok mu?
AjaxLeung

6
@AlexLeung - Postman kurulu bir uygulamadır. Web siteniz tarayıcımın Google'dan veri istemesini ve okuyabilmesini sağlayabilirse, web siteniz GMail Gelen Kutusu sayfamı isteyebilir ve tüm e-postalarımı okuyabilir. Bu korkunç olur.
Quentin

64

Benzer bir sorun yaşadım ve benim için , alıcı tarafın yanıtına aşağıdaki HTTP başlıklarını eklemek için kaynadı :

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

*Sonunda değil, yalnızca verileri gönderen ana bilgisayarın alan adını kullanmayı tercih edebilirsiniz . Sevmek*.example.com

Ancak bu, yalnızca sunucunun yapılandırmasına erişiminiz olduğunda uygulanabilir.


2
AngularJs'de yeniyim. Lütfen bunu nereye uygulayacağımı söyler misin?
ankitr

19
@Ankit Bu başlıkları AngularJS'de değil sunucuda eklemelisiniz .
Felipe

2
@techcraver - Sunucunun konfigürasyonuna operasyonel erişime ihtiyacınız yok - sadece başlıkları betiğinizden geçirin. Bir PHP arka header('Access-Control-Allow-Origin: *');
ucunuz

@davidkonrad: Tüm uygulamayı açısal v4.0'da oluşturdum. Bu başlıkları nereye
eklemem

@Pygirl, müşterileri köşeli bir şekilde yaptığına inanıyorum? Teknolojiye nasıl ve nerede bağlı olarak yanıt sunucu tarafına başlıklar eklemeniz gerekir. Açısal Http.get()veya benzerinden header('Access-Control-Allow-Origin: *')aradığınız bir PHP
betiğiyse

9

Flickr jsonp kullanmak için kaynak hizmetini kullanmayı deneyin:

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

Şablon:

<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>

4

Bu sorun, Aynı Kaynak İlkesi olan web uygulaması güvenlik modeli ilkesi nedeniyle oluşur . İlkeye göre, bir web tarayıcısı, bir ilk web sayfasında bulunan komut dosyalarının ikinci bir web sayfasındaki verilere erişmesine izin verir, ancak yalnızca her iki web sayfası aynı kökene sahipse. Bu, talep eden kişinin, talep eden sitenin ana bilgisayarı, protokolü ve bağlantı noktasıyla tam olarak eşleşmesi gerektiği anlamına gelir.

Bu CORS başlık sorununun üstesinden gelmek için birden fazla seçeneğimiz var.

  1. Proxy Kullanımı - Bu çözümde, istek proxy üzerinden gittiğinde aynı kaynak gibi görünecek şekilde bir proxy çalıştıracağız. NodeJS kullanıyorsanız , proxy işlerini yapmak için cors-everywhere'i kullanabilirsiniz . https://www.npmjs.com/package/cors-anywhere .

    Örnek : -

    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, etki alanları arası sorunlar hakkında endişelenmeden JSON verilerini göndermek için bir yöntemdir. XMLHttpRequest nesnesini kullanmaz, <script>onun yerine etiketi kullanır. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Sunucu Tarafı - Sunucu tarafında, çapraz kaynaklı istekleri etkinleştirmemiz gerekir. Öncelikle Ön Kontrollü istekleri (SEÇENEKLER) alacağız ve durum kodu 200 (tamam) olan isteğe izin vermemiz gerekiyor .

    Önceden kontrol edilen istekler, asıl isteğin gönderilmesinin güvenli olup olmadığını belirlemek için önce diğer etki alanındaki kaynağa bir HTTP SEÇENEKLERİ istek başlığı gönderir. Siteler arası istekler, kullanıcı verilerine etkileri olabileceğinden bu şekilde önceden kontrol edilir. Özellikle, GET veya POST dışında yöntemler kullanıyorsa bir istek önceden kontrol edilir. Ayrıca, POST, application / x-www-form-urlencoded, multipart / form-data veya text / plain dışında bir Content-Type ile istek verilerini göndermek için kullanılıyorsa, örneğin POST isteği sunucuya bir XML yükü gönderirse application / xml veya text / xml kullanılarak, istek önceden kontrol edilir. İstekte özel başlıkları ayarlar (örneğin, istek X-PINGOTHER gibi bir başlık kullanır)

    Yayı kullanıyorsanız, sadece aşağıdaki kodu eklemek sorunu çözecektir. Burada, ihtiyacınıza göre etkinleştirmek / devre dışı bırakmak önemli olmayan csrf belirtecini devre dışı bıraktım.

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

    Yaylı güvenlik kullanıyorsanız, yukarıdaki kodla birlikte aşağıdaki kodu kullanın.

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

2

Bunun gibi benzer bir sorunla karşılaştım, sorun arka uçta idi. Düğüm sunucusu (Express) kullanıyordum. Aşağıda gösterildiği gibi ön uçtan (açısal) bir istek aldım

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

Ama şu hatayı verdiHata

Bu, başlıklar olmadan express kullanılarak yazılan arka uç kodudur

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

Yönteme bir başlık ekledikten sonra sorun çözüldü

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

Node JS'de CORS'u Etkinleştirme hakkında daha fazla ayrıntı edinebilirsiniz.


1

Kendim cevapladı.

CORS açısal js + restEasy POST'ta

Sonunda bu geçici çözüme geldim: IE ile çalışmasının nedeni, IE'nin izin istemek için önce bir ön kontrol isteği yerine doğrudan bir POST göndermesidir. Ancak, filtrenin neden bir OPTIONS isteğini yönetemediğini ve filtrede açıklanmayan başlıkları varsayılan olarak gönderdiğini hala bilmiyorum (bu tek durum için bir geçersiz kılma gibi görünüyor ... belki bir dinlenmeEasy şey .. .)

Bu yüzden, dinlenme hizmetimde yanıtı yeniden yazan ve yanıt başlığını kullanarak yanıtta başlıkları içeren bir SEÇENEKLER yolu oluşturdum.

Daha önce herhangi biri bununla karşılaştıysa, bunu yapmanın temiz bir yolunu hala arıyorum.


1

Apache / HTTPD, çoğu kuruluşta veya evde Centos / etc kullanıyorsanız, ortalıkta olma eğilimindedir. Dolayısıyla, etrafınızda varsa, gerekli CORS başlıklarını eklemek için çok kolay bir şekilde bir proxy yapabilirsiniz.

Son zamanlarda epeyce acı çektiğim için burada bir blog yazım var. Ancak önemli olan, bunu /etc/httpd/conf/httpd.conf dosyanıza eklemek ve zaten "80 Dinle" yaptığınızdan emin olmaktır:

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

Bu, sunucunuz-ip: 80 / SomePath altındaki URL'lere yönelik tüm isteklerin http: // target-ip: 8080 / SomePath'e yönlendirilmesini sağlar. (CORS desteği olmayan API) yönlendirmesini ve doğru Erişim Kontrolü- ile geri dönmesini sağlar. Web uygulamanızla çalışmasına izin vermek için kaynak başlığı.

Elbette isterseniz portları değiştirebilir ve SomePath yerine tüm sunucuyu hedefleyebilirsiniz.


1

Bu yanıt, CORS'u desteklemeyen API'leri geçici olarak bulmanın iki yolunu özetlemektedir:

  • Bir CORS Proxy kullanın
  • API destekliyorsa JSONP kullanın

Çözümlerden biri, bir CORS PROXY kullanmaktır:

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>

Daha fazla bilgi için, bkz


API destekliyorsa JSONP kullanın:

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

PLNKR üzerinde DEMO

Daha fazla bilgi için, bkz


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

"Ayrıca WebApiConfig dosyanıza aşağıdaki kodu ekleyin" - Soru, Flickr'a bir istekte bulunmakla ilgilidir. Sunucuları OP'nin kontrolü altında değildir. Flickr muhtemelen ASP.NET de kullanmıyor.
Quentin

0

ngResourse modülünü kullanarak ön uçta CORS'u etkinleştirebiliriz. Ama en önemlisi, denetleyicide ajax isteğinde bulunurken bu kod parçasına sahip olmalıyız,

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

Ayrıca, komut dosyası bölümüne ngResourse CDN eklemeniz ve uygulama modülünde bir bağımlılık olarak eklemeniz gerekir.

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

Ardından, uygulama modülü bağımlılık bölümünde "ngResourse" kullanın

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.