AngularJ에서 CORS를 활성화하는 방법


147

Flickr 사진 검색 API 용 JavaScript를 사용하여 데모를 만들었습니다. 이제 AngularJ로 변환하고 있습니다. 인터넷에서 검색했으며 아래 구성을 찾았습니다.

구성 :

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
프록시에서 데이터를 요청해야하지만 여전히 플리커에서 직접 요청하고 있습니다.
Quentin

@quentin 빠른 답변 감사합니다. 데모 좀주세요
ankitr

1
flickr.com에서 프록시의 URL로 URL을 변경하면됩니다
Quentin

1
하지만 어떻게 플리커라고 부를까요? 플리커의 이미지가 필요합니다.
ankitr

2
클라이언트가 프록시를 호출합니다. 프록시 호출이 깜박입니다. 이것이 프록시가 의미하는 바입니다. 프록시 코드는 프록시가 아니며 정적 파일에서 JSON 및 JSONP를 제공하는 웹 서버입니다.
Quentin

답변:


193

당신은하지 않습니다. 요청한 서버는 CORS를 구현하여 웹 사이트 액세스에서 JavaScript를 부여해야합니다. 자바 스크립트는 다른 웹 사이트에 액세스 할 수있는 권한을 스스로 부여 할 수 없습니다.


1
대신 서버에서 Flickr에 요청하십시오.
Quentin

서버를 사용하지 않지만 node.js를 사용할 수 있습니다. 이것으로 길을 보여줄 수 있습니까?
ankitr

1
주석에 사용 가능한 공간이 아닙니다. 오히려 큰 주제입니다.
Quentin

https://www.google.comPOSTMAN과 같은 응용 프로그램 을 사용하여 응답을받을 수있는 이유는 무엇입니까? 하지만 AJAX 호출 GEThttps://www.google.com사용 하려고 하면 CORS 오류가 발생합니까? AJAX 호출을 POSTMAN의 호출과 유사하게 작동시킬 수있는 방법이 있습니까?
AjaxLeung

5
@AlexLeung — Postman은 설치된 응용 프로그램입니다. 웹 사이트에서 Google에 브라우저 요청 데이터를 만들어 읽을 수 있으면 웹 사이트에서 GMail받은 편지함 페이지를 요청하고 모든 이메일을 읽을 수 있습니다. 끔찍할 것입니다.
Quentin

64

비슷한 문제가 있었고 수신 측응답 으로 다음 HTTP 헤더를 추가하는 것으로 요약했습니다 .

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

*끝에는 사용하지 말고 데이터를 보내는 호스트의 도메인 이름 만 사용하는 것이 좋습니다 . 처럼*.example.com

그러나 이것은 서버 구성에 액세스 할 수있는 경우에만 가능합니다.


2
나는 AngularJs에 처음입니다. 이것을 구현할 위치를 알려주시겠습니까?
ankitr

17
@Ankit AngularJS가 아닌 서버에 이러한 헤더를 추가해야합니다 .
Felipe

2
@techcraver-서버 구성에 대한 운영 액세스가 필요하지 않습니다-스크립트 내에서 헤더를 전달하십시오. 당신이 경우 PHP는 것 백엔드header('Access-Control-Allow-Origin: *');
davidkonrad의

@ davidkonrad : angular v4에서 전체 앱을 만들었습니다. 이 헤더를 어디에 포함시켜야하는지 말할 수 있습니까? :
Pygirl

@Pygirl, 클라이언트 측을 각도로 만들었다 고 생각하십니까? 응답 서버 측에 헤더를 추가해야합니다. 기술에 따라 방법과 위치가 다릅니다. 앵귤러 Http.get()또는 유사 header('Access-Control-Allow-Origin: *')에서 호출하는 PHP 스크립트 인 경우 호출 된 PHP 스크립트에서 첫 번째 출력으로 추가하십시오 (예 : 실제 응답 JSON을 출력하기 전에)
davidkonrad

9

리소스 서비스를 사용하여 깜박임 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

이 문제는 동일한 원본 정책 인 웹 응용 프로그램 보안 모델 정책으로 인해 발생합니다. 정책 에서 웹 브라우저는 첫 번째 웹 페이지에 포함 된 스크립트가 두 번째 웹 페이지의 데이터에 액세스 할 수 있지만 두 웹 페이지의 원본이 동일한 경우에만 가능합니다. 즉, 요청자는 요청 사이트의 정확한 호스트, 프로토콜 및 포트와 일치해야합니다.

이 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. 서버 측 -서버 측에서 교차 출처 요청을 활성화해야합니다. 먼저 프리 플라이트 요청 (OPTIONS)을 받고 상태 코드 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("*");
                }
            };
        }
    }

    스프링 보안을 사용하는 경우 위 코드와 함께 아래 코드를 사용하십시오.

    @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

나는 이와 비슷한 문제가 발생했다. 문제는 백엔드에 있었다. 노드 서버 (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);
 })

메소드에 헤더를 추가 한 후 문제가 해결되었습니다.

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

Node JS에서 CORS 사용에 대한 자세한 정보를 얻을 수 있습니다.


1

나 스스로 대답했다.

CORS 앵귤러 js + restEasy on POST

마지막 으로이 해결 방법을 찾았습니다 .IE와 함께 일한 이유는 IE가 먼저 프리 플라이트 요청 대신 POST를 보내서 권한을 요청하기 때문입니다. 그러나 필터가 왜 OPTIONS 요청을 관리 할 수 ​​없었으며 필터에 설명되어 있지 않은 기본 헤더로 전송하는 이유를 여전히 알지 못합니다 (이 경우의 재정의처럼 보입니다 ... 아마 restEasy 일 .. .)

그래서 나머지 서비스에서 응답을 다시 작성하고 응답 헤더를 사용하여 응답에 헤더를 포함하는 OPTIONS 경로를 만들었습니다.

아무도 전에이 문제에 직면했을 때 여전히 깨끗한 방법을 찾고 있습니다.


1

Apache / HTTPD는 대부분의 기업에서 또는 Centos / etc를 집에서 사용하는 경우가 많습니다. 따라서 주변에 있다면 필요한 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- 오리진 헤더를 사용하여 웹 앱에서 작동 할 수 있습니다.

물론 원하는 경우 포트를 변경하고 SomePath 대신 전체 서버를 대상으로 지정할 수 있습니다.


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

PLNKR데모

자세한 내용은


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을 사용하지 않을 것입니다.
Quentin

0

ngResourse 모듈을 사용하여 프론트 엔드에서 CORS를 활성화 할 수 있습니다. 그러나 가장 중요한 것은 컨트롤러에서 아약스 요청을하는 동안이 코드 조각이 있어야한다는 것입니다.

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