如何在AngularJs中启用CORS

时间:2014-05-23 07:05:39

标签: javascript angularjs cors angularjs-http

我使用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://samurails.com/tutorial/cors-with-angular-js-and-sinatra/

修改

我在node.js中根据@Quentin:

的建议创建了一个代理服务器
var http = require('http');
var url = require('url');
var fs = require('fs');
var server;

server = http.createServer(function (req, res) {
    // your normal server code
    var path = url.parse(req.url).pathname;
    fs.readFile(__dirname + path, function (err, data) {
        if (err) {
            return send404(res);
        }
        res.writeHead(200, {'Content-Type':path == 'json.js' ? 'text/javascript' : 'text/html'});
        res.write(data, 'utf8');
        res.end();
    });
}),
server.listen(8001);
//using express to load customizes static files
var express = require("express"),
    app = express();

app.all("/api/*", function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
    res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
    return next();
});
app.use("/js", express.static(__dirname + '/js'));
app.listen(3001);

最终修改

我删除了授权标题

headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}

它运行正常。我有我想要的东西。 感谢大家参与这个问题

10 个答案:

答案 0 :(得分:177)

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

答案 1 :(得分:62)

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

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

您可能不希望最后使用*,而只使用发送数据的主机的域名。与*.example.com

一样

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

答案 2 :(得分: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>

答案 3 :(得分:3)

出现此问题是因为同源策略的Web应用程序安全模型策略在该策略下,Web浏览器允许第一个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对象。它使用<script>标记。 https://www.w3schools.com/js/js_json_jsonp.asp

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

    预先请求的请求首先将HTTP OPTIONS请求标头发送到另一个域上的资源,以确定实际请求是否可以安全发送。跨站点请求是这样预检的,因为它们可能对用户数据有影响。特别是,如果请求使用GET或POST以外的方法,则会预检。此外,如果使用POST来发送具有除application / x-www-form-urlencoded,multipart / form-data或text / plain之外的Content-Type的请求数据,例如,如果POST请求使用application / xml或text / xml将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("*");
                }
            };
        }
    }
    

    如果您使用弹簧安全性,请使用下面的代码以及上面的代码。

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

答案 4 :(得分:1)

自己回答。

CORS angular js + restEasy on POST

最后我来到这个解决方法: 它与IE一起使用的原因是因为IE直接发送POST而不是首先请求权限的预检请求。 但我仍然不知道为什么过滤器无法管理OPTIONS请求并默认发送过滤器中未描述的标题(似乎只是覆盖了这种情况......也许是一件轻松的事情...)

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

如果以前有人这么做的话,我仍然在寻找干净的方法。

答案 5 :(得分:1)

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

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

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

有关更多信息,请参见


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

有关更多信息,请参见

答案 6 :(得分: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);

答案 7 :(得分: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']);

答案 8 :(得分:0)

在大多数企业中,或者如果您在家中使用Centos / etc,Apache / HTTPD往往会出现。因此,如果您遇到这种情况,则可以非常轻松地进行代理以添加必要的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。

答案 9 :(得分:0)

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

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

但是它给出了以下错误The error

这是使用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);
})

您可以获取有关Enabling CORS on Node JS

的更多详细信息