Programing

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

lottogame 2020. 6. 20. 10:45
반응형

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


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

편집하다:

@Quentin의 제안에 따라 node.js에 프록시 서버를 만들었습니다.

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

그리고 그것은 잘 돌아가고 있습니다. 내가 원하는 것을 얻었습니다. 이 질문에 참여해 주셔서 감사합니다.


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


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

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

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

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


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

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

We have multiple options to over come this CORS header issue.

  1. Using Proxy - In this solution we will run a proxy such that when request goes through the proxy it will appear like it is some same origin. If you are using the nodeJS you can use cors-anywhere to do the proxy stuff. https://www.npmjs.com/package/cors-anywhere.

    Example:-

    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 is a method for sending JSON data without worrying about cross-domain issues.It does not use the XMLHttpRequest object.It uses the <script> tag instead. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Server Side - On server side we need to enable cross-origin requests. First we will get the Preflighted requests (OPTIONS) and we need to allow the request that is status code 200 (ok).

    Preflighted requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if it uses methods other than GET or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted. It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

    If you are using the spring just adding the bellow code will resolves the issue. Here I have disabled the csrf token that doesn't matter enable/disable according to your requirement.

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

    If you are using the spring security use below code along with above code.

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

I encountered a similar problem like this, problem was with the backend . I was using node server(Express). I had a get request from the frontend(angular) as shown below

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

But it gave the following errorThe error

This is the backend code written using express without the headers

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

After adding a header to the method problem was solved

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

You can get more details about Enabling CORS on Node JS


Answered by myself.

CORS angular js + restEasy on POST

Well finally I came to this workaround: The reason it worked with IE is because IE sends directly a POST instead of first a preflight request to ask for permission. But I still don't know why the filter wasn't able to manage an OPTIONS request and sends by default headers that aren't described in the filter (seems like an override for that only case ... maybe a restEasy thing ...)

So I created an OPTIONS path in my rest service that rewrites the reponse and includes the headers in the response using response header

I'm still looking for the clean way to do it if anybody faced this before.


Apache/HTTPD tends to be around in most enterprises or if you're using Centos/etc at home. So, if you have that around, you can do a proxy very easily to add the necessary CORS headers.

I have a blog post on this here as I suffered with it quite a few times recently. But the important bit is just adding this to your /etc/httpd/conf/httpd.conf file and ensuring you are already doing "Listen 80":

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

This ensures that all requests to URLs under your-server-ip:80/SomePath route to http://target-ip:8080/SomePath (the API without CORS support) and that they return with the correct Access-Control-Allow-Origin header to allow them to work with your web-app.

Of course you can change the ports and target the whole server rather than SomePath if you like.


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

we can enable CORS in the frontend by using the ngResourse module. But most importantly, we should have this piece of code while making the ajax request in the controller,

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

Also, you must add ngResourse CDN in the script part and add as a dependency in the app module.

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

Then use "ngResourse" in the app module dependency section

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

참고URL : https://stackoverflow.com/questions/23823010/how-to-enable-cors-in-angularjs

반응형