728x90

자바스크립트 개발환경에서 Ajax로 백엔드와 통신을 테스트 할때 걸리적 거리는 것 중 하나가 바로 CORS이다. 

CORS는 웹 브라우저의 기본 보안 모델로,
자바스크립트로 원격 리소스에 접근하고자 할 때, 자바스크립트를 내려 준 원천(Origin)이 아니면 Cross-Origin HTTP 요청으로 판단하여 요청을 허가하지 않게끔 한다.

그래서 웹 서버 설정이나 프로그래밍 방식으로 CORS 설정(HTTP 헤더 설정)을 통해 상호 통신이 가능케 한다.

이는 프로덕션 환경에서는 당연하겠지만, 개발 환경에서는 여간 불편한게 아니다.

개발 환경에서 서버 측을 직접 제어 할 수 있으면 별로 문제 될 것이 없으나, 그렇지 않을 경우 서버 측 담당자에게 CORS 설정을 요청해야 한다. 

만일 서버 측 환경이 다수의 서비스와 통신을 해야 하는 상황이라면 더욱 귀찮아 진다.

그래서 프론트엔드 단에서 Cross-Origin HTTP 요청이 가능하게끔 하는 방법이 자주 사용된다.

흔히 사용되는 방법으로는 Node.js의 http-proxy 관련 모듈을 사용해서 중간에 프록시 계층을 하나 두는 것인데, 이는 프록시 만을 위한 Node 응용프로그램을 별도로 띄워야 하는 점이 마음에 들지 않는다.


따라서 이 글에서는 프론트엔드 테스트 도구와 프록시 설정을 한방에 해결 할 수 있는 편리한 환경에 대해 소개하고자 한다.

몇 가지 선택지가 있으나 여기서는 Browser-Sync를 이용해 보자

1. 설치
 > npm install -g browser-sync

2. 프록시 설정 없이 테스트 돌려 보기
 > browser-sync start --server --files “*.*”

기본포트인 3000번 포트로 프론트엔드 파일들을 마치 웹 서버에서 실행하듯 테스트 해 볼 수 있다.
물론 Browser-Sync가 제공하는 각종 브라우저 동기화, 라이브로딩 등의 장점을 만끽하면서 말이다.
그런데 이렇게만 하면, CORS 통신을 하지 못하게 된다.

따라서 아래와 같이 실행.

3. 프록시 모드로 돌려보기

  > browser-sync start --proxy "localhost:8080" --serverStatic "public" --files "public"

정적리소스는 "public" 폴더에 있다고 가정하고 나머지 요청은 8080포트로 서비스 중인 서버 측으로 요청을 프록시하도록 한다.

이렇게 함으로써 정적파일은 정적파일대로 테스트 할 수 있고, 다른 도메인(포트)로 서비스 되고 있는 원격 API도 CORS상에서 호출이 가능해 진다.

음.. 아주 편하군...

끝!!!

그런데 이런 환경을 만들어 주는 게 비단, Browser-Sync만 있는 것이 아니다. 다음은 이와 같은 개발 환경을 가능케 해 주는 다른 모듈을 안내한다.

1) lite-server
- AngularJS 계의 거장(?)인 존파파께서 만들어준 로컬 서버 환경. Broswer-Sync를 기반으로 하고 있기 때문에 동일하게 동작한다. 물론 Angular 환경이 아니더라도 얼마던지 사용가능하다.

2) webpack-dev-server
- Angular2가 처음 출시될 때는 System.js에 lite-server를 사용했는데, 이후 버전 업이 되면서 최근 Angular-CLI는 webpack을 빌드도구를 채용하고 로컬 서버를 webpack-dev-server로 교체하였다.

역시나 Angular 환경이 아니더라도 webpack-dev-server를 사용할 수 있으며, 이 환경에서 CROS 설정이 가능하다.

다음 URL에서 아주 잘 설명하고 있다.

> https://webpack.github.io/docs/webpack-dev-server.html#proxy 


3) Angular환경 
- 만일 최신 Angular 프레임워크로 작업하고 있다면 ng serve 실행 시 프록시 설정을 추가 할 수 있다. 역시 다음 URL에서 아주 잘 설명하고 있다.

https://www.npmjs.com/package/angular-cli#proxy-to-backend



'모바일 > Javascript' 카테고리의 다른 글

Javascript Compiler, Babel  (10) 2017.03.16
[Angular] Angular Modules(NgModule)  (12) 2017.01.25
Isomorphic Javascript  (8) 2017.01.23
[Node] npm(node package manager)  (10) 2017.01.20
[Angular] Lazy Loading  (14) 2017.01.18
728x90

웹은 기본적으로 '동일출저정책(Same Origin Policy, SOP)' 정책을  따른다.

이는 보안을 위한 기본정책으로, SOP는 하나의 출처(Origin)에서 로드된 문서나 스크립트가 다른 출처에 존재하는 리소스와 상호작용하지 못하도록 제약을 두는 것이다.

그런데, 간혹 이런 제약이 웹 응용프로그램을 만드는데 걸림돌이 되기도 한다.
Ajax 통신이 활발해 지고, 다른 사이트에 존재하는 Open API와 상호통신이 필요한 경우와 매쉬업(Mash-up)으로 새로운 2차 응용물을 개발하게 되면서.. 등등.. 이는 간혹 걸림돌이 된다.

근래 Node.JS로 서버를 만들고, Aptana Studio 자체 내장 웹서버로 몇 가지 테스트를 하고 있는데, 두 환경은 서로 다른 별도의 포트(Port)에서 웹을 동작시키기 때문에 여지없이 Cross Domain 문제가 발생한다.


호출하는 모든 웹 리소스를, Node.JS로부터 다운로드 받아서 실행하는 구조로 HTTP 서버를 구현하면 SOP 정책을 따를 수 있겠으나, 그렇지 못한 개발환경도 있을 터이고, 실제 서비스 환경에서는 더욱이 서로 다른 도메인(포트 포함)간 상호작용이 필요할 것이다.

SOP 정책을 우회하기 위해서는, 서버 측의 설정이 필요한데, 위 그림에서 친철히 안내하고 있는 것처럼 Access-Control-Allow-Origin 헤더, 즉 크로스 도메인으로 허용할 도메인 목록이 헤더로 제공되어야 한다.
이것을 CORS(Cross-Origin Resource Sharing)를 이용한 SOP 정책 우회라 한다.

Node.JS 환경에서 이 설정을 해보자.
다음과 같이, Node 기반 HTTP 서버의 응답헤더에 추가 해준다.

가장 중요한 설정은, Access-Control-Allow-Origin으로 허용할 도메인(포트)을 추가한다.
여러 도메인이 있을 경우, 중복해서 지정을 하거나 '*' 를 이용해 전체 허용도 가능하다.

var app = require("express")();

app.use(function(req, res, next) {
 res.header("Access-Control-Allow-Origin", "
http://127.0.0.1:8020");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    next();
});

app.get('/users', function(req, res) { 
 var tempUsers = [{id:'park', city:'pusan'}, {id:'kim', city:'seoul'}]; 
    res.send(tempUsers);
});

app.listen(3002);
console.log("Listening on port 3002");

참고로 127.0.0.1:8020 도메인은, 필자의 Aptana Studio가 생성한 임의 주소이다.

이렇게 설정한 후, 클라이언트에서 요청하면 요청이 성공적으로 이뤄진다.

- 이 코드가 포함된 페이지는 127.0.0.1:8020 에 호스팅되어 동작한다.
<script>
window.onload = function(){
 var xhr = new XMLHttpRequest();
 xhr.onload = function(){
  console.log(xhr.response);  
 }; 
 xhr.open("GET", "http://127.0.0.1:3002/users");
 xhr.send();
}; 
</script>

그리고 언제나 그렇듯이 확장 라이브러리도 있다.
cors라는 이름의 Node.JS 확장인데, npm을 통해 설치하고 간단히 다음처럼 사용할 수 있다. 훨씬 간편하다.

var app = require("express")();

var cors = require('cors')();
app.use(cors);

그래도 언제나 보안은 중요한 문제이니, SOP 정책에 존중하면서, 필요시 아주 제한적으로 적용하는 것을 권장함.

 

'모바일 > Javascript' 카테고리의 다른 글

[Node.js] Node With IIS  (25) 2016.07.19
[AngularJS] 폼(form)과 유효성 검사  (12) 2016.07.18
[AngularJS] REST API 통신(with Node.js)  (10) 2016.07.15
[Node.js] socket.io를 활용한 웹채팅 구현  (735) 2016.07.15
[AngularJS] Route  (12) 2016.07.14