API서버는 프론트엔드도 다룰 수 있었야 한다.
왜냐하면 필요한 데이터를 저장하거나 불러오는 API서버를 구축할 수 있어야
동적활동을 할 수 있는 클라이언트를 구현할 수 있기 때문에
- SOP에 대해 이해할 수 있다.
- CORS에 대해 이해할 수 있다.
- CORS 동작 방식에 대해 이해할 수 있다.
- CORS 설정 방법을 이해한다.
SOP (Same-Origin-Policy) 동일 출처 정책
: 같은 출처의 리소스만 공유가 가능하다.
출처(Origin) | |||
프로토콜 | 호스트 | ||
포트 | |||
https:// | www.hahahah.com | :433 | /course |
출처는 프로토콜, 호스트, 포트의 조합이며 이 중 하나라도 다르면 동일한 출처가 아니다.
SOP는 왜 탄생했을까?
잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여준다.
SOP를 이용해 해킹 등의 위협헤서 더 안전해질 수 있다.
없다면?
나의 정보를 노리는 나쁜 사이트에 접속시
로그인자동저장 기능등으로 저장된 나의 개인정보를 가져가서
나쁜짓을 할 수있음
이러한 보안상 이점때문에 브라우저에서 기본적으로 사용한다.
하지만!
당장 내 로컬 환경에서 개발하는 클라이언트 서버를 따로 개발하게 된다면
이 또한 다른 출처가된다.
지도 api나 깃허브에서 정보를 받아오는것도 다 다른출처의 리소스를 사용하는 것이다.
그럼 또 어떡하나요?
CORS(Cross-origin Resource Sharing) 교차 출처 리소스 공유(MDN)
추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이
다른 출처의 선택한 자원에 접근 할 수 있는 권한을 부여하도록
브라우저에 알려주는 체제
웹 애플리케이션은 리소스가 자신의 출처와 다를 때 교차 출처 HTTP 요청을 실행한다.
CORS 동작방식
1. 프리플라이트 요청(Preflight Request)
실제 요청을 보내기 전에 OPTIONS 메서드로 사전 요청을 보내
해당 출처 리소스에 접근 권한이 있는지부터 확인하는 것
브라우저는 서버에 실제 요청을 보내기 전에 플라이트 요청을 보내고
응답 헤더의 Access-Control-Allow-Origin 으로 요청을 보낸 출처가 돌아오면
실제 요청을 보낸다.
요청을 보낸 출처가 접근 권한이 없다면?
브라우저에서 CORS에러 발생
왜 필요한가요?
- 실제 요청을 보내기 전에 미리 접근 권한 확인 가능
실제 요청을 처음부터 전체를 보내는 것보다 리소스 측면에서 효율적
- CORS에 대비가 되어있지 않은 서버를 보호할 수 있다.
CORS 이전에 만들어진 서버들은 SOP요청만 들어오는 상황을 고려하고 만들어짐
=> 다른 출처에서 들어오는 요청에 대한 대비가 X
서버에 바로 요청을 보내면?
응답을 보내기 전에 우선 요청을 처리
브라우저는 응답을 받은 후에야 CORS 권한이 없다는 것을 인지
브라우저가 에러창을 띄운 후에는 이미 요청 수행되어버림
만약에 요청이 DELETE나 PUT처럼 서버의 정보를 ........ 끔찍
CORS에 대비가 되어있지 않은 서버라도
프리플라이트요청을 먼저 보내게되면
프리플라이트 요청에서 CORS 에러 발생
=> 기본사양이 된 이유
2. 단순 요청(Simple Request)
특정 조건이 만족되면 프리플라이트 요청을 생략하고 요청
특정 조건?
1. GET, HEAD, POST요청 중 하나
2. 자동 설정 헤더제외 특정 헤더의 값만 수동으로 설정할 수 있다.
3. 인증 정보를 포함한 요청(Credentialed Request)
요청헤더에 인증 정보를 담아 보내는 요청
출처가 다를 경우에는 별도의 설정을 하지 않으면 쿠키(민감한 정보)를 보낼 수 없다.
이 경우 프론트, 서버 양측 모두 CORS 설정이 필요
- 프론트
요청 헤더에 withCredentials : true
- 서버:
응답 헤더에 Access-Control-Allow-Credentials : true
Access-Control-Allow-Origin 설정할 때
모든 출처를 허용한다는 뜻의 와일드카드(*)로 설정하면 에러난다.
인증 정보를 다루는 만큼 출처를 정확하게 설정해야함
CORS 설정 방법
1. Node.js 서버
const http = require('http');
const server = http.createServer((request, response) => {
// 모든 도메인
response.setHeader("Access-Control-Allow-Origin", "*");
// 특정 도메인
response.setHeader("Access-Control-Allow-Origin", "https://codestates.com");
// 인증 정보를 포함한 요청을 받을 경우
response.setHeader("Access-Control-Allow-Credentials", "true");
})
2. Express 서버
const cors = require("cors");
const app = express();
//모든 도메인
app.use(cors());
//특정 도메인
const options = {
origin: "https://codestates.com", // 접근 권한을 부여하는 도메인
credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
optionsSuccessStatus: 200, // 응답 상태 200으로 설정
};
app.use(cors(options));
//특정 요청
app.get("/example/:id", cors(), function (req, res, next) {
res.json({ msg: "example" });
});
In Sprint
writeHead(상태코드, 헤더 객체) : HTTP응답의 헤더정보를 설정하는 메서드
end() : HTTP응답을 종료하는 메서드.
선택적으로 인자를 받으며 HTTP응답의 마지막 부분을 나타내는 문자열.
인자를 생락하면 빈 문자열("") 전송
요청 메서드가 POST이고 End Point(url)가 /upper /lower 일 때를 의미
HTTP 요청의 body를 읽어서 문자열을 대/소문자로 변환해서 HTTP응답으로 전송하는 로직이다
사실 이곳에서 코드를 들고왔는데 무슨소린지 몰랐다. 그래서 하나씩 뜯어보도록 하자!
on 이벤트 핸들러 함수?
HTTP요청의 data이벤트와 end이벤트를 처리하기 위해 request 객체에 두개의 이벤트 핸들러를 등록한다.
body를 빈배열로 먼저 만들어주고 request 객체의 data 이벤트를 리스닝한다.
data 이벤트 핸들러는 클라이언트가 보내는 데이터를 읽어서 body 배열에 데이터 조각(chunk)를 추가한다.
따라서 HTTP요청의 body 데이터가 조각(Chunk) 단위로 발생될 때마다 실행된다.
이 과정에서 받은 데이터 조각은 버퍼(buffer)형태로 전달되는데 그게 무엇인지는 그만알아보자.
request.on('end', ()=>{...}) 같이 request 객체의 end 이벤트를 리스닝한다.
end 이벤트는 위에서 보았듯이 HTTP 요청의 body 데이터가 모두 전송된 후에 발생하는 이벤트이다.
여기서 body = Buffer.concat(body).toString ~~ 과 같이 body 배열에 저장된 데이터 조각(chunk)들을 합쳐서
하나의 버퍼(buffer)로 만들고 이를 문자열 형태로 변환(toString)해서 body 변수에 저장한다.
=> 데이터를 문자열로 얻을 수 있다.
response.writeHead(200, defaultCorsHeader)와같이 응답상태코드와 응답헤더를 설정해주고
response.end(body.toUpperCase()) 와 같이 HTTP 응답의 본문(body)을 위에서 문자열로 받은 데이터를 대문자로 변환한다.
'JavaScript' 카테고리의 다른 글
[JS] 호이스팅 (0) | 2023.04.23 |
---|---|
UI/UX (2) | 2023.04.13 |
Rest API (6) | 2023.03.29 |
HTTP/네트워크 기초 (1) | 2023.03.28 |
React State & Props (2) | 2023.03.24 |