🍃프로그래머스 백엔드 데브코스 4기 교육과정을 듣고 정리한 글입니다.🍃
SPA(Single-Page Application)
- 사용자 요청에 의해 URL 변경 시 화면 전체의 로드 없이 일부반만 동적으로 렌더링
- AJAX를 이용해서 대부분 리소스들(HTML, CSS, JS)은 어플리케이션 로드시 한번만 읽음
- JSON같은 데이터만 어플리케이션 실행중에 읽어오고 관련된 화면을 동적으로 변경
서버사이드 라우팅 처리(JSP, Thymeleaf)
- 서버는 클라이언트 요청을 받아 해당하는 데이터를 가져오거나 작업을 수행한 후, 클라이언트에 결과를 제공
- 클라이언트가 새로운 URL을 요청하면, 서버는 해당 URL에 대한 페이지 전체를 다시 렌더링하고 클라이언트에 전달
- 각 요청마다 서버에서 작업을 수행하기 때문에, 많은 요청이 동시에 발생하면 서버 부하가 증가
클라이언트 라우팅 처리(View.js, React.js)
- 클라이언트는 초기 페이지를 로드한 후 서버로부터 데이터를 가져와 라우팅 처리를 수행
- URL이 변경될 때, 클라이언트는 필요한 데이터만 서버로 요청하여 해당 데이터만 업데이트
- 이미 로드된 페이지에서 필요한 데이터를 서버로부터 받아와 클라이언트 측에서 처리하므로 서버 부하가 감소
- 웹 애플리케이션에서 동적으로 URL을 변경하고, 뒤로 가기/앞으로 가기 버튼과 같은 탐색 동작을 처리할 수 있HTML5 히스토리 API 사용
Origin(출처)
그림 출처
- Protolcol 과 Host 그리고 Port 까지 모두 합친 URL을 의미
SOP(Same-Origin Policy)
- 동일한 출처에서만 리소스를 공유할 수 있다라는 정책
- 동일하지 않는 다른 출처의 악성 스크립트가 실행되지 않도록 브라우저에서 사전에 방지하기 위함
출처 구분
그림 출처
https://www.domain.com:3000
출처에 대한 여러 URL에 따른 동일 출처 비교
- 같은 프로토콜, 호스트, 포트를 사용한다면, 그 뒤의 다른 요소는 다르더라도 같은 출처로 인정
- 반대로 프로토콜, 호스트, 포트 중 하나라도 자신의 출처와 다를경우 브라우저는 SOP 정책상 차단
(CORS 에러)
- 이는 브라우저의 정책이기 때문에 브라우저를 통하지 않고 서버 간에 통신을 할때는 정책이 적용되지 않음
- 즉, 클라이언트에서 API 요청을 하는게 아니라, 프록시 서버에서 다른 출처의 서버로 API 요청하면 CORS 에러 해결
CORS(Cross-Origin Resource Sharing)
웹페이지에서 다른 출처에 있는 리소스를 가져와 사용하는 일은 매우 흔한 일이기 때문에 이를 전부 차단할 수 없다. 그래서 나온 정책이 CORS
- 다른 출처의 리소스 공유에 대한 허용/비허용 정책
- SOP 정책을 위반해도 CORS 정책에 따르면 다른 출처의 리소스라도 허용함
CORS 3가지 동작 방식
Preflight Request
그림 참조
- 브라우저가 요청을 한번에 보내지 않고 예비 요청과 본 요청으로 나눠 서버로 전송
- 이때 예비요청을 preflight이라 함
Simple Request
그림 참조
- 예비요청 없이 바로 본 요청을 보내고, 응답에 따라 CORS 정책 위반 여부를 검사
- 단, simple request 시나리오를 위해선 특정 조건을 만족해야 함
- HTTP method가
GET, HEAD, POST
중 하나여야 함
Accept, Accept-Language, Content-Language, Content-type, DPR, Downlink, Save-Data, Viewport-Width, Width
이외의 헤더를 사용하면 안됨
- Content-Type 사용하는 경우
application/x-www-form-urlencoded, multipart/form-data, text/plain
만 허용
Credentialed Request
- 다른 출처 간 통신의 보안을 강화하고 싶을 때 사용
- 클라이언트에서 인증 정보를 보내도록 credentials 옵션을 설정해야 함
- same-origin(기본값): 같은 출처 간 요청에만 인증 정보를 담을 수 있음
- include: 모든 요청에 인증 정보를 담을 수 있음
- omit: 모든 요청에 인증 정보를 담지 않음
- 서버에서 인증된 요청에 대한 응답 헤더의 Access-Control-Allow-Credentials 항목을 true로 설정해야 함
CORS 에러 해결 방법
클라이언트에서 프록시 사용
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
};
- localhost에서 react와 spring 서버를 통신하는 상황이라면 프록시 서버를 spring 서버의 주소로 설정
- OPEN API를 사용하는 경우 모든 출처를 허용한 프록시 서버를 사용
서버에서 Access-Control-Allow-Origin 헤더 세팅
@RestController
public class ExampleController {
@CrossOrigin(origins = "http://localhost:3000", methods = RequestMethod.POST
@GetMapping("/api/data")
public String getData() {
return "Hello from Spring server!";
}
}
- 직접 spring 서버에서 HTTP 헤더 설정을 통해 출처를 허용하게 하는 방법
- 특정 HTTP 메서드의 출처만 허용하게 적용 가능