【问题标题】:How to enable CORS in AngularJs如何在 AngularJs 中启用 CORS
【发布时间】:2018-10-19 22:46:34
【问题描述】:

我使用 JavaScript 为 Flickr 照片搜索 API 创建了一个演示。 现在我将它转换为 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 cannot load URL. Origin not allowed by Access-Control-Allow-Origin

http://goo.gl/JuS5B1

【问题讨论】:

  • 你必须从你的代理请求数据,你还是直接从 flickr 请求数据。
  • @quentin 感谢您的快速回复。请给我一个演示。
  • 您只需将 URL 从 flickr.com 更改为您的代理的 URL
  • 但是我要怎么称呼 flickr?因为我需要来自 flickr 的图片。
  • 客户端调用代理。代理调用 flickr。这就是代理的意思。 (您的代理代码……不是代理,它是用于从静态文件提供 JSON 和 JSONP 的 Web 服务器)。

标签: javascript angularjs xmlhttprequest cors


【解决方案1】:

此答案概述了解决不支持 CORS 的 API 的两种方法:

  • 使用 CORS 代理
  • 如果 API 支持 JSONP,则使用它

一种解决方法是使用 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;
 }) 

DEMO on PLNKR

有关详细信息,请参阅

【讨论】:

    【解决方案2】:

    我遇到了类似的问题,问题出在后端。我正在使用节点服务器(Express)。我有一个来自前端(角度)的获取请求,如下所示

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

    添加header后方法问题解决了

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

    您可以获取更多关于Enabling CORS on Node JS的详细信息

    【讨论】:

      【解决方案3】:

      我们可以通过使用 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']);

      【讨论】:

        【解决方案4】:

        Apache/HTTPD 倾向于在大多数企业中使用,或者如果您在家里使用 Centos/etc。所以,如果你有这个,你可以很容易地做一个代理来添加必要的 CORS 标头。

        我有一篇关于 here 的博客文章,因为我最近遭受了很多次。但重要的是只需将其添加到您的 /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。

        【讨论】:

          【解决方案5】:

          出现此问题的原因是 Web 应用程序安全模型策略是 同源策略 在该策略下,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 对象。而是使用&lt;script&gt; 标签。 https://www.w3schools.com/js/js_json_jsonp.asp

          3. 服务器端 - 在服务器端,我们需要启用跨域请求。 首先,我们将获得预检请求 (OPTIONS),我们需要允许状态代码为 200 (ok) 的请求。

            预检请求首先向另一个域上的资源发送一个 HTTP OPTIONS 请求标头,以确定实际请求是否可以安全发送。跨站点请求是这样预检的,因为它们可能对用户数据有影响。特别是,如果请求使用 GET 或 POST 以外的方法,则它会被预检。此外,如果 POST 用于发送 Content-Type 不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 的请求数据,例如如果 POST 请求使用 application/xml 或 text/xml 将 XML 有效负载发送到服务器,则预检请求。 它在请求中设置自定义标头(例如,请求使用诸如 X-PINGOTHER 之类的标头)

            如果您使用的是 spring,只需添加以下代码即可解决问题。 在这里,我已根据您的要求禁用了无关紧要的 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();
                }
            
            }
            

          【讨论】:

            【解决方案6】:
                    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。
            【解决方案7】:

            我自己回答。

            CORS angular js + restEasy on POST

            最后我找到了这个解决方法: 它与 IE 一起工作的原因是因为 IE 直接发送一个 POST 而不是首先发送一个预检请求来请求许可。 但我仍然不知道为什么过滤器无法管理 OPTIONS 请求并默认发送过滤器中未描述的标头(似乎是唯一情况下的覆盖......也许是一个restEasy的事情...... .)

            所以我在我的休息服务中创建了一个 OPTIONS 路径,它重写了响应并使用响应标头在响应中包含标头

            如果以前有人遇到过这种情况,我仍在寻找干净的方法。

            【讨论】:

              【解决方案8】:

              我遇到了类似的问题,对我来说,归结为在接收端响应中添加以下 HTTP 标头:

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

              您可能不希望在末尾使用*,而只使用发送数据的主机的域名。赞*.example.com

              但这只有在您可以访问服务器的配置时才可行。

              【讨论】:

              • 我是 AngularJs 的新手。请问你能告诉我在哪里实现这个吗?
              • @Ankit 你需要在服务器中添加这些头文件,而不是在AngularJS中。
              • @techcraver - 您不需要对服务器配置的操作访问权限 - 只需从脚本中传递标头即可。如果您有 PHP 后端,它将是 header('Access-Control-Allow-Origin: *');
              • @davidkonrad :我在 Angular v4 中创建了整个应用程序。你能告诉我必须在哪里包含这些标题吗:/
              • @Pygirl,我相信您已经使客户端变得有角度了?您需要将标头添加到响应服务器端,具体方式和位置取决于技术。如果它是您从角度 Http.get() 或类似名称调用的 PHP 脚本,请添加 header('Access-Control-Allow-Origin: *') 作为被调用 PHP 脚本中的第一个输出(即在您输出实际响应之前,JSON 等等。
              【解决方案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>
              

              【讨论】:

                【解决方案10】:

                你没有。您向其发出请求的服务器必须实施 CORS 以从您的网站访问中授予 JavaScript。您的 JavaScript 无法授予自己访问其他网站的权限。

                【讨论】:

                • 改为从您的服务器向 Flickr 发出请求。
                • 我没有使用服务器,但我可以使用 node.js。你能给我指路吗?
                • 不在评论的可用空间中。这是相当多的主题。
                • 为什么我可以使用 POSTMAN 之类的应用程序从 https://www.google.com 获得响应,但是当我尝试使用 AJAX 调用从 https://www.google.com 发送 GET 时出现 CORS 错误?有没有办法让 AJAX 调用的行为类似于来自 POSTMAN 的调用?
                • @AlexLeung — Postman 是一个已安装的应用程序。如果您的网站可以让我的浏览器向 Google 请求数据并阅读它,那么您的网站可以请求我的 GMail 收件箱页面并阅读我所有的电子邮件。那太可怕了。
                猜你喜欢
                • 1970-01-01
                • 2016-10-25
                • 2014-07-29
                • 2015-05-27
                • 2020-11-24
                • 2021-04-14
                相关资源
                最近更新 更多