Cách bật CORS trong AngularJs


147

Tôi đã tạo một bản demo bằng cách sử dụng JavaScript cho API tìm kiếm ảnh Flickr. Bây giờ tôi đang chuyển đổi nó sang AngularJs. Tôi đã tìm kiếm trên internet và tìm thấy cấu hình dưới đây.

Cấu hình:

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

Dịch vụ:

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

Điều khiển:

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

Nhưng tôi vẫn nhận được lỗi tương tự. Dưới đây là một số liên kết tôi đã thử:

XMLHttpRequest không thể tải URL. Nguồn gốc không được phép bởi Access-Control-Cho phép-Origin

http://goo.gl/JuS5B1


1
Bạn phải yêu cầu dữ liệu từ proxy của mình, bạn vẫn đang yêu cầu dữ liệu trực tiếp từ flickr.
Quentin

@quentin Cảm ơn đã trả lời nhanh chóng. Bạn có thể vui lòng cho tôi một bản demo
ankitr

1
Bạn chỉ cần thay đổi URL từ flickr.com thành URL của proxy của bạn
Quentin

1
Nhưng làm thế nào tôi sẽ gọi flickr? như tôi cần những hình ảnh từ flickr.
ankitr

2
Khách hàng gọi proxy. Các proxy gọi flickr. Đó là những gì proxy có nghĩa. (Mã proxy của bạn không phải là proxy, đó là máy chủ web để phục vụ JSON và JSONP từ các tệp tĩnh).
Quentin

Câu trả lời:


193

Bạn không. Máy chủ bạn đang yêu cầu phải triển khai CORS để cấp JavaScript từ quyền truy cập trang web của bạn. JavaScript của bạn không thể cấp quyền truy cập trang web khác.


1
Thay vào đó, hãy yêu cầu Flickr từ máy chủ của bạn.
Quentin

Tôi không sử dụng máy chủ nhưng tôi có thể sử dụng node.js. Bạn có thể chỉ cho tôi cách với điều này?
ankitr

1
Không có trong không gian có sẵn trong một bình luận. Đó là một tập hợp lớn các chủ đề.
Quentin

Tại sao nó mà tôi có thể nhận được một phản hồi từ https://www.google.comsử dụng một ứng dụng như Postman, nhưng khi tôi cố gắng GETtừ https://www.google.comsử dụng một cuộc gọi AJAX tôi nhận được lỗi CORS? Có cách nào để tôi có thể thực hiện cuộc gọi AJAX tương tự như cuộc gọi từ POSTMAN không?
AjaxLeung

5
@AlexLeung - Postman là một ứng dụng được cài đặt. Nếu trang web của bạn có thể làm cho trình duyệt của tôi yêu cầu dữ liệu từ Google và đọc nó, thì trang web của bạn có thể yêu cầu trang Hộp thư đến của tôi và đọc tất cả email của tôi. Điều đó sẽ rất tệ.
Quentin

64

Tôi đã gặp một vấn đề tương tự và đối với tôi, nó đã được bổ sung thêm các tiêu đề HTTP sau vào phản hồi của phần cuối nhận :

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

Bạn có thể không muốn sử dụng *ở cuối, mà chỉ tên miền của máy chủ gửi dữ liệu. Giống*.example.com

Nhưng điều này chỉ khả thi khi bạn có quyền truy cập vào cấu hình của máy chủ.


2
Tôi là người mới trong AngularJs. Xin vui lòng cho tôi biết nơi để thực hiện điều này?
ankitr

17
@Ankit Bạn cần thêm các tiêu đề này trong máy chủ , không phải trong AngularJS.
Felipe

2
@techcraver - Bạn không cần quyền truy cập hoạt động vào cấu hình của máy chủ - chỉ cần chuyển các tiêu đề từ trong tập lệnh của bạn. Nếu bạn có một phụ trợ PHP thì nó sẽ làheader('Access-Control-Allow-Origin: *');
davidkonrad

@davidkonrad: Tôi đã tạo toàn bộ ứng dụng trong v4 góc. Bạn có thể cho biết nơi tôi phải bao gồm các tiêu đề này: /
Pygirl

@Pygirl, tôi tin bạn đã làm cho khách hàng ở góc cạnh? Bạn cần thêm các tiêu đề vào máy chủ phản hồi, cách thức và địa điểm phụ thuộc vào công nghệ. Nếu đó là một tập lệnh PHP mà bạn gọi từ một góc Http.get()hoặc tương tự, hãy thêm header('Access-Control-Allow-Origin: *')vào như là đầu ra đầu tiên trong tập lệnh PHP được gọi (tức là trước khi bạn đưa ra phản hồi thực tế, JSON, từ bao giờ.
davidkonrad

9

Hãy thử sử dụng dịch vụ tài nguyên để tiêu thụ 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' });
});

Bản mẫu:

<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

Sự cố này xảy ra do chính sách mô hình bảo mật ứng dụng web là Chính sách xuất xứ tương tự Theo chính sách, trình duyệt web cho phép các tập lệnh có trong trang web đầu tiên truy cập dữ liệu trong trang web thứ hai, nhưng chỉ khi cả hai trang web có cùng nguồn gốc. Điều đó có nghĩa là người yêu cầu phải phù hợp với máy chủ, giao thức và cổng chính xác của trang yêu cầu.

Chúng tôi có nhiều tùy chọn để vượt qua vấn đề tiêu đề CORS này.

  1. Sử dụng Proxy - Trong giải pháp này, chúng tôi sẽ chạy proxy sao cho khi yêu cầu đi qua proxy, nó sẽ xuất hiện giống như một nguồn gốc giống nhau. Nếu bạn đang sử dụng nodeJS, bạn có thể sử dụng cors-bất cứ nơi nào để thực hiện công cụ proxy. https://www.npmjs.com/package/cors-anywhere .

    Ví dụ : -

    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 là một phương thức để gửi dữ liệu JSON mà không phải lo lắng về các vấn đề tên miền chéo. Nó không sử dụng đối tượng XMLHttpRequest <script>. Thay vào đó, nó sử dụng thẻ. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Phía máy chủ - Về phía máy chủ, chúng tôi cần kích hoạt các yêu cầu xuất xứ chéo. Đầu tiên, chúng tôi sẽ nhận được các yêu cầu Preflighted (TÙY CHỌN) và chúng tôi cần cho phép yêu cầu đó là mã trạng thái 200 (ok).

    Các yêu cầu được chiếu trước trước tiên gửi tiêu đề yêu cầu HTTP TÙY CHỌN đến tài nguyên trên tên miền khác, để xác định xem yêu cầu thực tế có an toàn để gửi hay không. Các yêu cầu trên nhiều trang web được chiếu trước như thế này vì chúng có thể có liên quan đến dữ liệu người dùng. Cụ thể, một yêu cầu được chiếu trước nếu nó sử dụng các phương thức khác ngoài GET hoặc POST. Ngoài ra, nếu POST được sử dụng để gửi dữ liệu yêu cầu với Loại nội dung không phải là application / x-www-form-urlencoding, Multipart / form-data hoặc text / plain, ví dụ: nếu yêu cầu POST gửi tải trọng XML đến máy chủ sử dụng application / xml hoặc text / xml, sau đó yêu cầu được chiếu trước. Nó đặt các tiêu đề tùy chỉnh trong yêu cầu (ví dụ: yêu cầu sử dụng một tiêu đề như X-PINGOTHER)

    Nếu bạn đang sử dụng lò xo chỉ cần thêm mã dưới đây sẽ giải quyết vấn đề. Ở đây tôi đã vô hiệu hóa mã thông báo csrf không quan trọng bật / tắt theo yêu cầu của bạn.

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

    Nếu bạn đang sử dụng bảo mật mùa xuân, hãy sử dụng mã bên dưới cùng với mã ở trê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

Tôi gặp một vấn đề tương tự như thế này, vấn đề là với phần phụ trợ. Tôi đã sử dụng máy chủ nút (Express). Tôi đã có một yêu cầu nhận từ frontend (góc) như hình dưới đây

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

Nhưng nó đã đưa ra lỗi sauLỗi

Đây là mã phụ trợ được viết bằng cách sử dụng express mà không có tiêu đề

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

Sau khi thêm một tiêu đề cho vấn đề phương pháp đã được giải quyết

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

Bạn có thể biết thêm chi tiết về việc kích hoạt CORS trên Node JS


1

Trả lời bởi chính tôi.

CORS góc js + nghỉ ngơi dễ dàng trên POST

Cuối cùng tôi cũng tìm ra cách giải quyết này: Lý do nó hoạt động với IE là vì IE gửi trực tiếp một POST thay vì trước tiên là một yêu cầu preflight để xin phép. Nhưng tôi vẫn không biết tại sao bộ lọc không thể quản lý yêu cầu TÙY CHỌN và gửi theo các tiêu đề mặc định không được mô tả trong bộ lọc (có vẻ như là ghi đè cho trường hợp duy nhất đó ... có thể là một điều dễ dàng .. .)

Vì vậy, tôi đã tạo một đường dẫn TÙY CHỌN trong dịch vụ nghỉ ngơi của mình để viết lại phản hồi và bao gồm các tiêu đề trong phản hồi bằng tiêu đề phản hồi

Tôi vẫn đang tìm cách sạch sẽ để làm điều đó nếu có ai phải đối mặt với điều này trước đây.


1

Apache / HTTPD có xu hướng xuất hiện ở hầu hết các doanh nghiệp hoặc nếu bạn đang sử dụng Centos / etc tại nhà. Vì vậy, nếu bạn có xung quanh đó, bạn có thể thực hiện proxy rất dễ dàng để thêm các tiêu đề CORS cần thiết.

Tôi có một bài viết trên blog này ở đây vì tôi đã chịu đựng nó khá nhiều lần gần đây. Nhưng điều quan trọng là chỉ cần thêm phần này vào tệp /etc/httpd/conf/httpd.conf của bạn và đảm bảo bạn đã thực hiện "Nghe 80":

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

Điều này đảm bảo rằng tất cả các yêu cầu tới URL trong máy chủ-ip của bạn: 80 / somePath định tuyến tới http: // target-ip: 8080 / somePath (API không có hỗ trợ CORS) và chúng sẽ trả về với Quyền truy cập-Kiểm soát-Cho phép- Tiêu đề gốc để cho phép chúng hoạt động với ứng dụng web của bạn.

Tất nhiên, bạn có thể thay đổi các cổng và nhắm mục tiêu toàn bộ máy chủ thay vì somePath nếu bạn muốn.


1

Câu trả lời này nêu ra hai cách để giải quyết các API không hỗ trợ CORS:

  • Sử dụng Proxy CORS
  • Sử dụng JSONP nếu API hỗ trợ nó

Một cách giải quyết khác là sử dụng 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>

Để biết thêm thông tin, xem


Sử dụng JSONP nếu API hỗ trợ 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;
 }) 

Các DEMO trên PLNKR

Để biết thêm thông tin, xem


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

"Và cũng thêm mã sau vào tệp WebApiConfig của bạn" - Câu hỏi là về việc yêu cầu Flickr. Máy chủ của họ không thuộc quyền kiểm soát của OP. Flickr có lẽ cũng không sử dụng ASP.NET.
Quentin

0

chúng ta có thể kích hoạt CORS ở lối vào bằng cách sử dụng mô-đun ngResference. Nhưng quan trọng nhất, chúng ta nên có đoạn mã này trong khi thực hiện yêu cầu ajax trong bộ điều khiển,

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

Ngoài ra, bạn phải thêm ngResference CDN trong phần tập lệnh và thêm dưới dạng phụ thuộc trong mô-đun ứng dụng.

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

Sau đó sử dụng "ngResference" trong phần phụ thuộc mô-đun ứng dụng

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.