AngularJsでCORSを有効にする方法


147

Flickr写真検索APIのJavaScriptを使用してデモを作成しました。今、私はそれをAngularJsに変換しています。私はインターネットで検索し、以下の構成を見つけました。

構成:

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

サービス:

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

コントローラ:

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

しかし、それでも同じエラーが発生しました。ここに私が試したいくつかのリンクがあります:

XMLHttpRequestがURLを読み込めません。オリジンはAccess-Control-Allow-Originで許可されていません

http://goo.gl/JuS5B1


1
プロキシからデータを要求する必要がありますが、flickrから直接データを要求しています。
クエンティン

@quentin迅速な返信ありがとうございます。デモをお願いします。
ankitr 2014年

1
URLをflickr.comからプロキシのURLに変更するだけ
Quentin

1
しかし、どうやってflickrを呼び出すのですか?flickrからの画像が必要なので。
ankitr 2014年

2
クライアントはプロキシを呼び出します。プロキシはflickrを呼び出します。それがプロキシの意味です。(プロキシコードはプロキシではなく、静的ファイルからJSONとJSONPを提供するWebサーバーです)。
クエンティン

回答:


193

あなたはしません。リクエストを送信するサーバーは、WebサイトからのJavaScriptアクセスを許可するCORSを実装する必要があります。JavaScriptは、別のWebサイトへのアクセスを許可することはできません。


1
代わりに、サーバーからFlickrにリクエストを送信してください。
クエンティン2014年

サーバーを使用していませんが、node.jsを使用できます。これで道を教えてくれませんか?
ankitr 2014年

1
コメントで使用できるスペースにはありません。それはかなり大きなトピックのセットです。
クエンティン2014年

なぜそれが私がからの応答を得ることができるということですhttps://www.google.comPOSTMANのようなアプリケーションを使用して、私がしようとしたときGETから、https://www.google.comAJAX呼び出しを使用して、私はCORSのエラーを取得しますか?AJAX呼び出しをPOSTMANからの呼び出しと同様に動作させる方法はありませんか?
AjaxLeung 2016年

5
@AlexLeung — Postmanはインストールされたアプリケーションです。あなたのウェブサイトが私のブラウザにGoogleからのデータを要求し、それを読むことができれば、あなたのウェブサイトは私のGMail受信箱ページを要求し、私のすべてのメールを読むことができます。それはひどいでしょう。
クエンティン

64

私にも同様の問題があり、要約すると、受信側の応答に次のHTTPヘッダーを追加することです。

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

*最後にを使用するのではなく、データを送信するホストのドメイン名のみを使用することもできます。お気に入り*.example.com

ただし、これは、サーバーの構成にアクセスできる場合にのみ可能です。


2
私はAngularJsの新人です。これを実装する場所を教えてください。
ankitr 2014年

17
@Ankitこれらのヘッダーは、AngularJSではなくサーバーに追加する必要があります
フェリペ

2
@techcraver-サーバーの構成に操作アクセスする必要はありません。スクリプト内からヘッダーを渡すだけです。PHPバックエンドがある場合、それはheader('Access-Control-Allow-Origin: *');
davidkonrad

@davidkonrad:アプリ全体をangular v4で作成しました。これらのヘッダーを含める必要がある場所を教えてください:/
Pygirl

@Pygirl、クライアントサイドを角張ったと思いますか?ヘッダーと応答サーバーサイドを追加する必要があります。方法と場所はテクノロジーによって異なります。Angular Http.get()などから呼び出すPHPスクリプトの場合header('Access-Control-Allow-Origin: *')は、呼び出されるPHPスクリプトの最初の出力として追加します(つまり、実際の応答を出力する前に、JSONなど)
davidkonrad

9

リソースサービスを使用して、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' });
});

テンプレート:

<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

この問題は、同一生成元ポリシーであるWebアプリケーションセキュリティモデルポリシーが原因で発生します。このポリシーでは、Webブラウザは、最初のWebページに含まれるスクリプトが2番目のWebページのデータにアクセスすることを許可します。つまり、リクエスタは、リクエストするサイトの正確なホスト、プロトコル、およびポートと一致する必要があります。

このCORSヘッダーの問題を解決するには、複数のオプションがあります。

  1. プロキシの使用 -このソリューションでは、リクエストがプロキシを通過するときに、同じ発信元のように見えるようにプロキシを実行します。nodeJSを使用している場合は、cors -anywhereを使用してプロキシ関連を行うことができます。https://www.npmjs.com/package/cors-anywhere

    :-

    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は、クロスドメインの問題を心配せずにJSONデータを送信するための方法です。XMLHttpRequestオブジェクトを使用せず、<script>代わりにタグを使用します。https://www.w3schools.com/js/js_json_jsonp.asp

  3. サーバー側 -サーバー側では、クロスオリジンリクエストを有効にする必要があります。最初にプリフライトリクエスト(オプション)を取得し、ステータスコード200(ok)のリクエストを許可する必要があります。

    プリフライトされたリクエストは、最初にHTTP OPTIONSリクエストヘッダーを他のドメインのリソースに送信して、実際のリクエストが安全に送信できるかどうかを判断します。クロスサイトリクエストは、ユーザーデータに影響を与える可能性があるため、このようにプリフライトされます。特に、GETまたはPOST以外のメソッドを使用するリクエストはプリフライトされます。また、POSTを使用して、application / x-www-form-urlencoded、multipart / form-data、text / plain以外のContent-Typeでリクエストデータを送信する場合、たとえば、POSTリクエストがXMLペイロードをサーバーに送信する場合application / xmlまたはtext / xmlを使用すると、リクエストはプリフライトされます。リクエストにカスタムヘッダーを設定します(たとえば、リクエストはX-PINGOTHERなどのヘッダーを使用します)

    スプリングを使用している場合は、次のコードを追加するだけで問題が解決します。ここでは、要件に応じて有効化/無効化を問わないcsrfトークンを無効にしました。

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

    Spring Securityを使用している場合は、上記のコードとともに以下のコードを使用してください。

    @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

私はこのような同様の問題に遭遇しました、問題はバックエンドにありました。ノードサーバー(エクスプレス)を使用していました。以下に示すように、フロントエンド(angular)からgetリクエストがありました

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

しかし、それは次のエラーを出しましたエラー

これは、ヘッダーなしでexpressを使用して記述されたバックエンドコードです。

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

メソッドにヘッダーを追加した後、問題は解決しました

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

Node JSでCORSを有効にする方法の詳細を確認できます


1

自分で答えた。

CORS angular js + restEOSTY on POST

さてついに私はこの回避策に到達しました:IEで動作する理由は、IEが最初にプリフライトリクエストを許可する代わりにPOSTを直接送信するためです。しかし、なぜフィルターがOPTIONSリクエストを管理できず、フィルターに記述されていないヘッダーがデフォルトで送信されたのかはまだわかりません(その唯一のケースのオーバーライドのように思われます...おそらくRESTEasyのこと。 。)

そこで、応答を書き換え、応答ヘッダーを使用して応答にヘッダーを含めるOPTIONSパスをRESTサービスに作成しました

誰かが以前にこれに直面した場合、私はまだそれを行うためのクリーンな方法を探しています。


1

Apache / HTTPDは、ほとんどの企業や、自宅でCentosなどを使用している場合によく使用されます。そのため、それができれば、プロキシを簡単に実行して、必要なCORSヘッダーを追加できます。

私は最近これに何度も苦しんだので、ここにこれに関するブログ投稿があります。しかし重要なのは、これを/etc/httpd/conf/httpd.confファイルに追加し、すでに「Listen 80」を実行していることを確認することです。

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

これにより、your-server-ip:80 / SomePathの下のURLへのすべてのリクエストがhttp:// target-ip:8080 / SomePath(CORSサポートのないAPI)にルーティングされ、正しいAccess-Control-Allow-で返されます。それらがあなたのウェブアプリで動作することを可能にするOriginヘッダー。

もちろん、ポートを変更して、SomePathではなくサーバー全体を対象にすることもできます。


1

この回答は、CORSをサポートしないAPIを回避する2つの方法の概要を示しています。

  • CORSプロキシを使用する
  • APIがサポートする場合はJSONPを使用する

回避策の1つは、CORSプロキシを使用することです。

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>

詳細については、


APIがサポートしている場合はJSONPを使用します。

 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上のDEMO

詳細については、


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

「また、次のコードをWebApiConfigファイルに追加します」— Flickrへのリクエストについての質問です。それらのサーバーはOPの制御下にありません。FlickrもおそらくASP.NETを使用していません。
クエンティン

0

ngResourseモジュールを使用して、フロントエンドでCORSを有効にすることができます。しかし、最も重要なのは、コントローラーでajaxリクエストを行うときにこのコードを用意することです。

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

また、ngResourse CDNをスクリプトパーツに追加し、依存関係としてアプリモジュールに追加する必要があります。

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

次に、アプリケーションモジュールの依存関係セクションで「ngResourse」を使用します

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.