CORS / Node.js HTTP (Mini node server 만들기) 6/17 수정

young·2022년 6월 16일
0

5/25~6/22 Section 2 TIL

목록 보기
24/27

S2U10 W8D4
어제 react effect hook으로 rest api 불러오기에 이어서
오늘은 mini node server을 만들어본다
두둥... 재밌을 것 같아 (제발)


✅ TIL

  • CORS
    SOP

  • Node.js http 모듈로 Mini node server 만들기


1️⃣ CORS

SOP

Same-Origin Policy
동일 출처 정책
같은 origin의 리소스만 공유 가능하다는 정책
모든 브라우저는 기본적으로 SOP 정책을 사용한다.

Origin = 출처
Same-Origin = 출처를 이루는 프로토콜, 호스트, 포트가 동일해야 함

동일 출처에서만 리소스가 공유 가능함으로써 공격 받을 수 있는 경로를 줄여준다.
= 다른 사이트와의 리소스 공유를 제한한다.
= 잠재적으로 해로울 수 있는 문서를 분리하는 것.

but ...

클라이언트와 서버를 따로 개발한다면, 둘은 출처가 달라지고,
API 사용 등으로 다른 출처를 사용할 일이 생긴다.

CORS

Cross-Origin Resource Sharing
교차 출처 리소스 공유

SOP 기반의, 다른 출처의 리소스가 접근 권한을 얻을 수 있는 공유 방식
추가 HTTP 헤더를 사용하여 다른 출처의 리소스에 접근할 수 있는 권한을 부여한다.

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다. -mdn


2️⃣ CORS 동작 방식 3가지

1. 프리플라이트 요청 (Preflight Request)

실제 요청을 보내기 전에,
OPTIONS Method 요청으로 해당 출처 리소스에 접근 권한이 있는지 확인부터 한다.

응답 헤더에 Access-Control-Allow-Origin: 해당 출처 라고 오면
실제 요청을 보낸다.

응답 헤더에 Access-Control-Allow-Origin가 없으면,
브라우저에서 CORS 에러를 띄우고,
실제 요청이 전달되지 않는다.

💡 프리플라이트 요청이 필요한 이유

  • 실제 요청을 보내기 전에 권한 확인을 먼저 함으로 리소스 측면에서 효율적이다.

  • CORS 대비가 되어있지 않은 서버를 보호할 수 있다.
    CORS 등장 전, SOP 요청만 들어오는 상황을 고려하고 만들어진 서버는
    응답을 보내기 전에 요청 처리를 먼저 한다.
    브라우저가 에러를 띄운 후에는 이미 요청이 수행된 상태다.
    하지만 Preflight 요청을 보내면 Preflight 요청에서 CORS 에러를 띄우기 때문에 Cross-Origin 요청 실행을 방지한다.

2. 단순 요청 (Simple Request)

특정 조건이 만족되면 preflight 요청을 생략하고 실제 요청을 보내는 것

  1. GET, HEAD, POST 요청이어야 한다.
  2. 헤더의 Accept, Accept-Language, Content-Language, Content-Type 값만 수동으로 설정할 수 있다.
    Content-Type 헤더에는 application/x-www-form-urlencoded, multipart/form-data, text/plain 값만 허용한다.

3. 인증정보를 포함한 요청(Credentialed Request)

요청 헤더에 인증 정보를 담아 보내는 것

출처가 다를 경우에는 별도의 설정을 하지 않으면 쿠키를 보낼 수 없다.
= 프론트, 서버 모두 CORS 설정을 해야 한다.

프론트 측은 요청 헤더에 withCredentials : true를 넣어야 한다.

서버 측은 응답 헤더에 Access-Control-Allow-Credentials : true를 넣어야 한다.
Access-Control-Allow-Credentials와일드카드(*) 로 설정하면 에러가 발생한다. (= 모든 출처를 허용한다는 뜻)

인증 정보는 민감한 정보이기 때문에 출처를 정확하게 설정해주어야 한다.


3️⃣ CORS 설정 방법

헤더의 값을 설정하여 CORS 설정을 할 수 있다.

1. Node.js 서버

HTTP 서버 응답 헤더

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 서버

Express 프레임워크를 사용하여 서버를 만드는 경우
cors 미들웨어를 사용해서 간단하게 CORS를 설정할 수 있다.

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" });
});

Mini Node Server 만들기

http.createServer //http 모듈의 createServer method 사용
node server.js	//Node.js 서버 실행

npm install nodemon //서버를 live로 볼 수 있게 해주는 개발도구

설치 후 다음 구문을 package.json 파일의 scripts 안에 작성한다.
"start": "nodemon server/basic-server.js"

Preflight request 처리

if (opitions method면) cors 설정을 돌려준다

if(request.method === 'OPTIONS') {
  console.log(`http request method is ${request.method}, url is ${request.url}`);
  response.writeHead(200, defaultCorsHeader);
  response.end();
  return; 	//return을 해야 다른 if문 영향 안 받고 빠져 나온다.
}

(6/17수정)
return을 작성하지 않고 다른 if문들을 else if로 변경해주니 동일하게 작동한다.

/upper, /lower endpoint 구현하기

method와 url에 따라서 분기 시킨다.
if (method === POST && url === /upper) 이면 대문자로 응답을 돌려준다

  if(request.method === 'POST' && request.url === '/upper') {
    let body = [];
    request.on('data', (chunk) => { 
      body.push(chunk);
    })
    request.on('end', () => { 
      body = Buffer.concat(body).toString();
      console.log(`http request method is ${request.method}, url is ${request.url}`);
      response.writeHead(200, defaultCorsHeader);
      response.end(body.toUpperCase());
    });
    return;	//마찬가지로 return 필수
  }

(6/17수정)
return을 작성하지 않고 다른 if문들을 else if로 변경해주니 동일하게 작동한다.

error 처리

POST method 외에는 error로 처리 (bad request)

  else {
    response.statusCode = 404;
    response.end();
    return;
  }

(6/17수정)
return을 작성하지 않고 다른 if문들을 else if로 변경해주니 동일하게 작동한다.


HTTP 트랜잭션 해부

profile
즐겁게 공부하고 꾸준히 기록하는 나의 프론트엔드 공부일지

0개의 댓글