-
[Spring] SPA와 CORS에 대해서Backend/Spring 2022. 8. 17. 17:17728x90
SPA (Single-Page Application)
단일 페이지 웹 어플리케이션
사용자 인터랙션에 의해 URL 변경 시 화면 전체의 로드가 없이 화면의 일부분만 동적으로 렌더링하여 데스크탑 어플리케이션과 비슷한 유저 경험을 제공한다.
- AJAX를 이용해서 대부분의 리소스(HTML, CSS, Script)들은 어플리케이션 로드시 한번 읽는다.
- JSON과 같은 데이터만 어플리케이션 실행 중에 읽어오고 관련된 화면을 변경시킨다.
- 전통적인 방법
- JSP와 Thymeleaf와 다르게 보여지는 내용을 서버에서 처리하지 않고 브라우저에서 처리하는 것
- 요청을 보내면 html을 반환해서 이를 렌더링함
- SPA 방법
- 화면에서 변경이 일어날 때 DOM을 이용해서 동적으로 브라우저에서 그리는 것
- 요청을 해서 처음에 HTML이 로드가 되고 관련된 CSS, JS 파일이 읽어져서 어플리케이션 로드가 딱 한번만 이루어짐
- 그 다음부터는 클라이언트가 AJAX라는 기술을 이용해서 URL을 이용하지 않고 백엔드에서 요청을 보냄
- 서버가 응답을 받아서 JSON응답을 줌
- 클라이언트는 JSON을 파싱해서 읽은 다음에 이 데이터를 가지고 DOM(Document Object Model) 프로그램에 append되어 렌더링이 일어남
- 일반 웹 애플리케이션 : 전체가 다 렌더링됨
- 레이아웃에 관한 기능도 Thymeleaf 같은 템플릿엔진을 이용해서 서버 쪽에서 처리
- 단일 페이지 웹 애플리케이션 : URL이 변경 시 특정 영역만 렌더링됨
- 전체가 렌더링이 안되고 부분만 렌더링되도록 할 수 있음
- 이때 DOM을 manulpulate(조작)해서 렌더링에 DOM을 append하고 내용들을 채움
- 세션 : http 프로토콜은 stateless 처음 요청에 대해 두번째 요청은 첫번째 요청에 반응할 수 없음
- 세션은 사용자가 웹서비스에 접근해서 머문 일정시간동안 유지되는 상태
- 로그인하면 사용자 정보 등이 세션에 저장됨
- 특정 요청이 그 사용자에 대한 요청임을 알기 위해 쿠키를 이용해서 세션 ID를 매 요청마다 쿠키에 실음
- 세션이 유지되는 동안에 요청은 그 사용자에 대한 요청이라는 것을 서버가 알 수 있음
- 세션은 서버에서 관리 - 쿠키를 가지고 요청에 대한 사용자를 찾음
- 세션은 사용자가 웹서비스에 접근해서 머문 일정시간동안 유지되는 상태
- SPA
- 세션을 가지고 하는 경우 사용자 데이터 모델에 다양한 정보(메뉴, 롤,,)를 넣다보면 너무 커지기 때문에 이것의 일부를 브라우저에서 메모리에 들고 있음 -> 로컬 스토리지
- AJAX로 요청을 하면 메뉴 정보, user Id, customer정보(미리 그려져있는 정보?) 등을 로컬 스토리지에 잠시 담아뒀다가 reload하면 가져옴
- DOM프로그램을 사용해서 변경할 부분만 바꿀 수 있기 때문에 필요할 때 마다 데이터를 요청
- 일반적으로 DOM 바꾸면 URL이 안바뀜
- 세션을 가지고 하는 경우 사용자 데이터 모델에 다양한 정보(메뉴, 롤,,)를 넣다보면 너무 커지기 때문에 이것의 일부를 브라우저에서 메모리에 들고 있음 -> 로컬 스토리지
- 서버사이드 라우팅 처리
- 서버 쪽에서 return할 때 view가 맵핑되기 때문에 URL이 바뀜
- 라우팅에 대한 처리를 서버쪽에서 함
- 클라이언트 라우팅 처리
- 돔만 바꾸고 URL을 안바꿀 때 refresh하면은 다시 읽기 때문에 원래 return된 view가 보임
- 해시태그나 html5 히스토리를 이용하면 URL을 바뀌지만 서버에 요청을 안보냄
- 바뀐 URL에 대해 클라이언트 쪽에서 catch를 해서 렌더링하게 됨
- 순수 자바 스크립트 기능
- 서버가 view 리턴하는 코드가 없어지게됨 -> 템플릿엔진으로 데이터와 html을 만들어서 리턴하는 행위 없어짐
- JSON, xml을 리턴하는 api만 가지게 됨
CORS(Cross-Origin Resource Sharing)
배경
웹 애플리케이션이 복잡해지면서 하나의 호스트만 접근하는 것이 아니라 다양한 호스트에 접근해서 정보를 가져와야 한다. 다양한 호스트에 접근하고 다양한 리소스를 필요로 하다보니까 보안이 중요하게 되었다. 이때 사용자를 악의적인 행위로부터 보호하기 위해서 브라우저는 동일 출처(same origin)에서만 리소스의 접근을 허용하게 하는 same origin policy를 만들게 되었다.
따라서 CORS는 http header를 이용해서 애플리케이션의 다른 출처(origin)의 다양한 리소스에 접근할 수 있게 하는 매커니즘을 말한다. 동일한 출처에서 리소스를 접근하지 않으면 CORS가 발생하는 것이다.
여기서 동일한 출처란?
- 호스트, 프로토콜, 포트가 다 동일하면 same origin이라고 한다.
- CORS 에러 발생 예시
- spring boot와 리액트로 된 프로젝트의 경우 spring boot 서버는 8080 포트이고 리액트 서버 포트는 3000번이기 때문에 CORS 에러가 발생
=> proxy를 이용해서 해결 가능
- spring boot와 리액트로 된 프로젝트의 경우 spring boot 서버는 8080 포트이고 리액트 서버 포트는 3000번이기 때문에 CORS 에러가 발생
CORS 흐름
- 예비요청을 보내는지 여부에 따라 CORS흐름이 바뀜
- 예비요청은 단순요청이 아닐 때만 보냄
단순요청이란?
# GET, HEAD, POST 중 하나의 메서드를 사용할 때
# 유저 에이전트(브라우저)가 자동으로 설정한 헤더 외에, 프론트엔드 자바스크립트 코드에서 수동으로 설정할 수 있는 헤더는 다음의 헤더 뿐
- Accept
- Accept-Language
- Content-Language
- Content-Type
# Content-Type 헤더는 다음의 값만 허용
- application/x-www-form-urlencoded
-
mulipart/form-data
- text/plain
# 요청에 사용된 XMLHttpRequestUpload 객체에는 이벤트 리스너가 등록되어 있지 않아야함
- XMLHttpRequestUpload.upload 프로퍼티를 사용해 접근
# 요청에 ReadableStream 객체가 사용되지 않아야 함
출처 : https://developer.mozilla.org/ko/docs/Web/HTTP/CORS1. 단순요청이 아닌 경우
- 예비 요청(CORS Preflight)
- option이라는 http 요청으로 보냄
- origin은 클라이언트 host가 됨
- 서버가 access를 허용하는 origin에 대해 url이나 *(모든 CORS를 허용함)를 보냄
2. 단순요청인 경우
- 요청했을 때 서버가 Access-Control-Allow-Origin을 주지 않으면 fail하게 됨
728x90'Backend > Spring' 카테고리의 다른 글