2019-09 Angular를 처음 접하게 되였다.

1년동안 Angular를 사용하면서 느낀 장, 단점을 공유 하고자 한다.
앞으로 사용하면서 느낀 장, 단점도 지속적으로 추가할 예정이다.

 

* 지극히 주관적인 의견입니다. 참고만 해주세요~

 

장점

  • 컴포넌트 단위로 모듈화를 할 수 있어 수정이 용이하다.
  • 화면 구성을 Angular에서 제공하는 기능들을 이용하여 구현하기 쉽다.
    • html에서 for문을 사용, if문으로 조건 걸어 사용, css, style을 데이터에 따라 변경 등을 이용하여 구현한다. 하지만 Angular와 같이 다른 프레임 워크도 충분히 가능하지만 Angular가 기능이 훨씬 많고 편리하다고 생각한다.
    • html 태그에서 사용할수 있는 attribute를 직접 만들어서 사용할 수 있다.
      • <div TestDirective></div> 라고 작성하면 TestDirective attribute에 더블클릭 이벤트를 넣어서 사용할 수 있다.

단점

  • 러닝 커브가 너무 심하다.
    • JavaScript와 jQuery를 접하고 시작했는데도 typescript와 reactive programming, funcational programing등의 파생되는 학습이 필요하여 익숙해지는데까지 시간이 오래 걸린다.
  • 버전 변경이 잦아 업그레이드를 자주 하기에는 리스크가 너무 크다.
    • 6개월에 한번씩 버전이 나온다. 최근 버전은 8.x에서 10.1.4로 업그레이드 하였는데 토이 프로젝트를 업그레이드 후 에러 잡는데 상당한 시간이 걸렸다.

 

많은 프레임 워크를 접한 것은 아니지만 무엇보다 Angular의 기능을 이용하면서 화면 구성하는 게 재미있다.

2020년 9월 29일 Angular 버전을 아래와 같이 변경 

이전 버전 : 8.2.x => 현재 버전 : 10.1.4

업그레이드 후 상황

변경 전 정상 작동 되던 프로젝트가 변경 후 컴파일 에러가 발생 한다.

에러는 아래의 두가지 에러가 발생했다.

 

  • ngStyle, ngFor, ngIf 등 CommonModule에서 제공하는 Directive를 인식하지 못하는 에러
* Error 1

error NG8002: Can't bind to 'ngModel' since it isn't a known property of 'input'.
  • Custom Elements를 인식하지 못하는 에러
* Error 2

error NG8001: 'app-xxx' is not a known element: 1. If 'app-xxx' is an Angular component, then verify that it is part of this module. 2. If 'app-xxx' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

해결하는 과정

버전을 업그레이드한 후 발생한 문제였으니 package.json에 dependency에 있는 각 모듈들의 버전을 확인해보고 새로운 프로젝트를 만들어서 기존 프로젝트와 비교도 해보고 프로젝트를 하나 하나 뜯어보는 등 많은 방법으로 에러를 잡으려고 노력하였지만 원인 조차 찾지 못했다.

원인

프로젝트를 조금씩 지워나가면서 원인을 찾는 과정에서 app.module.ts에 사용하고자 하는 component를 import하면 에러가 사라지는 것을 발견하였다. 그것을 힌트로 얻어 app-routing.module.ts에서 각 component들을 호출하는 방식을 의심했다. 구체적인 원인은 찾지 못했지만 에러가 발생하는 원인은 lazy loading에 있었다.

 

기존에는 아래와 같이 app-routing.module.ts를 구성했다면

* app-routing.module.ts

const routes : Routes = [
 { path : '', component: TestComponent }
];

export const AppRoutingModule = RouterModule.forRoot(routes);

해결된 방법은 아래와 같다.

* app-routing.module.ts

const routes : Routes = [
 { path : '', loadChildren: () => import('./test/testmodule').then((m) => m.TestModule) }
];

export const AppRoutingModule = RouterModule.forRoot(routes);

---------------------------------------------------------------------------------------------------------------------------

* test.module.ts

const routes : Routes = [
 { path : '', component: TestComponent }
];

@NgModule({  
    declarations: [TestComponent],  
    imports: [RouterModule.forChild(routes)],
})
export class TestModule { }

차이점으로는 기존에는 app-routing.module.ts에서 TestComponent를 바로 호출했다면, 현재는 app-routing.module.ts에서 TestModule을 호출하고 TestModule이 TestComponent를 호출하는 방식으로 변경되어 일주일 만에 문제가 해결되었다.

* 아래의 참고 자료에서 Angular Lazy-loading 참고

 

Angular 내부적으로 Compile시 체크하는 로직이 변경된 것이 아닌가 하는 추측을 해보지만 정확하지는 않다.

추 후 이에 대한 원인을 알게 된다면 다시 재작성 하려고 한다.


Angular Issues에 보면 저와 비슷한 에러를 가지고 있는 사람들이 많은것 같습니다. 저와 마찬가지로 몇 주 동안 해결하지 못한 사람도 있는것 같아 조금이나마 도움이 되고자 이 글을 작성하였습니다. 동일한 방법으로 해결 될 지는 모르겠지만 이 글이 작은 실마리가 되었으면 합니다.

부족한 부분도 많고 잘못 이해한 부분도 있으리라 생각합니다. 언제든지 지적해주세요.

 

읽어주셔서 감사합니다.

 

참고 자료

교차 출처 리소스 공유(Cross-origin resource sharing, CORS), 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다. 웹페이지는 교차 출처 이미지, 스타일시트, 스크립트, iframe, 동영상을 자유로이 임베드할 수 있다. 특정한 도메인 간(cross-domain) 요청, 특히 Ajax 요청은 동일-출처 보안 정책에 의해 기본적으로 금지된다.

환경

  • Spring Boot (Server)

    • Version : 2.3.0.RELEASE 

    • Port : 8080

  • Angular (Client)

    • Version : 8.2.14

    • Port : 4300


위의 환경 정보에서 Spring Boot, Angular의 Port를 보면 CORS 상황인걸 확인할 수 있다.

Angular에서 카카오 API 인증 요청

  • Kakao Request Guide

GET /oauth/authorize?client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}&response_type=code HTTP/1.1
Host: kauth.kakao.com

위의 Guide를 보면 client_id, redirect_uri, response_type을 매개변수로 받는것을 알 수 있다.

  • Sample 1

http://kauth.kakao.com//oauth/authorize?client_id=123123123123123123123&redirect_uri=http://localhost:8080/kakao&response_type=code

위의 Sample을 확인해 보면 아래의 3가지 매개변수를 입력한걸 알 수 있다.

client_id : 123123123123123123123

redirect_uri : http://localhost:8080/oauth/kakao

reponse_type : code

 

여기서 redirect_uri가 중요하다.

 

oAuth2의 기본 개념은 Angular(Client)가 Kakao API를 호출하면 Angular(Client)에게 응답을 주는게 맞다.

하지만 Rest API 호출 상황에서는 Kakao API가 Angular(Client)에게 응답을 줄수 있는 방법이 없다.

그래서 redirect_uri를 Spring Boot(Server)로 받아야 한다.

Rest API로 Angular(Client)에서 응답 받는 방법이 없다고 판단하였으나 혹시 모르니 조금 더 찾아보려 한다.
※ Angular(Client)가 Kakao API의 JavaScript 고급가이드대로 Login 하면 가능하다.
하지만 Kakao API 문서에 따르면 앞으로 oAuth 중요 정보인 Refresh Token을 제공하지 않을 계획이라고 명시하였다.
Kakao Developers JavaScript 로그인 API 고급가이드를 참고바란다.

Spring Boot 로직 처리

@GetMapping("/kakao")
public void kakaoLogin(String code, HttpServletRequest request, HttpServletResponse response) throws Exception {
	try {
		RestTemplate rest = new RestTemplate();
          // 사용자 인증정보 받기 위한 세팅
          MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
          map.add("grant_type", "authorization_code");
          map.add("client_id", "12312312312312312312312312");
          map.add("redirect_uri", "http://localhost:8080/oauth/kakao");
          map.add("code", code);

          HttpHeaders headers = new HttpHeaders();
          headers.add("Context-type", "application/json");

          HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);

          // 사용자 인증정보 요청
          ResponseEntity<Map> rs = rest.postForEntity("https://kauth.kakao.com/oauth/token", entity, Map.class);

          // access_token, refresh_token Get
          String Access = rs.getBody().get("access_token").toString();
          String Refresh = rs.getBody().get("refresh_token").toString();

          // 회원 가입 프로세스
          {
              ...
          }

          // Cookie, Response			
          {
              Cookie accessCookie 	= // 쿠키생성
              Cookie refreshCookie 	= // 쿠키생성

              response.addCookie(accessCookie);
              response.addCookie(refreshCookie);

              // Angular로 Redirect
              response.sendRedirect("http://localhost:4300");
          }

	} catch (Exception e) {
		e.printStackTrace();
	}
}

위의 소스를 보면 code를 Kakao API에서 redirect 받는다.

 

받은 인증 코드를 이용하여 사용자 인증정보(access_token, refresh_token)을 요청하고 Cookie를 만들어 response.sendRedirect를 이용하여 Angular(Client)에 redirect하면 정상적으로 Kakao Login이 완료된다.


두서 없이 Kakao Login을 처음 구현하면서 격은 문제점을 보완해서 글을 작성하였습니다. 처음 접하는거라 많이 부족하기도 하고 모르는 것도 많았습니다. 부족한 부분이나 틀린 부분이 있다면 언제든지 지적 해주세요.

 

읽어주셔서 감사합니다.

 

참고 자료

 Domain 호출 순서

  1. 사용자가 웹 브라우저에 www.naver.com을 입력한다.

  2. ROOT DNS 서버는 com DNS 서버에 주소를 묻는다.

  3. 전달 받은 주소를 com DNS 서버에 묻는다.

  4. com DNS 서버는 Local DNS서버에게 주소를 전달한다.

  5. Local DNS 서버는 전달받은 주소를 사용자에게 알려준다.

▶ Host 파일을 확인

  1. Domain을 호출하기 전에 Local에 있는 hosts에 해당 Domain이 존재 하는지 확인한다.

  2. Domain이 존재 한다면 해당 IP를 받아 호출한다.

  3. Domain이 존재 하지 않는다면 DNS 서버에서 검색을 하여 IP를 받아 호출한다.

▶ Host 파일에 IP, Domain을 추가하는 이유

  • 도메인 접속 속도 향상

  • 보안 관련 문제 대처

 

참고자료

+ Recent posts