● 오늘 공부한 것
- CORS
● CORS (Cross-Origin-Resource-Sharing)
오늘은 CORS에 대해서 포스팅 해볼까 합니다. 오늘은 CORS를 정리하기만해도 오늘의 몫을 다했다고 볼 수 있겠네요. 거지같은 ㅇㅣ CORS 오류 .. 도댁체가 이것이 멀까요? ● 우리는 웹서버를 개발하
ddaeunbb.tistory.com
- 과제
HTTP 트랜잭션 해부 | Node.js
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
nodejs.org
과제를 막상 하려니 너무 막막했는데요.. 트랜잭션 해부를 보니까 많이 이해가되었습니다.
http.createServer([options][,requestlistener])
모든 node 웹서버 앱은 createServer를 써서 웹서버 객체를 만들어야 한다.
// 서버 열기 전 준비, (http 불러오고 포트열기)
const http = require('http');
const PORT = 4999;
const ip = 'localhost';
// 서버 생성
const server = http.createServer();
server.on("request", (request, response) => {
// 여기에 작업
});
위의 createServer가 반환한 server 객체는 EventEmitter(클래스임)의 인스턴스이다. EventEmitter에서 server객체를 생성하고 리스너를 추가한다.
이 객체들은 하나 이상의 함수를 특정 event에 붙여서 실행될 수 있게 허락하는 .on() 함수를 가지고 있다.
이 객체들이 이벤트를 발생(emit)시키면 그 특정 event에 붙어있는 하나 이상의 함수들을 전부 비동기적으로 호출시킨다.
호출된 함수들로 인해 발생한 어떠한 리턴 값은 다 무시되고 버려진다.
아래 축약문으로 쓸 수도 있다.
const http = require("http");
const server = http.createServer((request, response) => {
// 여기에 작업
});
CORS에서 프리플라이트 방식을 구현하기 위해 OPTIONS 메서드로 들어오게되면 헤더에 아래 4개를 담아 보낸다.
- Access-Control-Allow-Origin
- Access-Control-Allow-Method
- Access-Control-Allow-Headers
- Access-Control-Max-Age
const defaultCorsHeader = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
'Access-Control-Max-Age': 10
};
if (request.method === 'OPTIONS'){
response.writeHead(200, defaultCorsHeader);
response.end('hello mini-server sprints');
};
하지만 POST로 들어오게 되면 클라이언트가 보낸 바디의 data를 가져온뒤 데이터 가공을 거쳐 헤더와 바디를 다시 적어 응답을 클라이언트에게 보낸다.
if (request.method === 'POST'){
let body = [];
request
.on('data', (chunk)=>{ // chunck 를 body 배열에 담아,
body.push(chunk)
})
.on('end', ()=>{ // end 이벤트에서 이어붙인 다음 문자열로 만듦.
body = Buffer.concat(body).toString();
response.writeHead(201, defaultCorsHeader);
if (request.url === '/upper'){ // 대문자로 요청했을 경우
response.end(body.toUpperCase()); // 바디에 대문자로 전환해 보낸다.
} else if (request.url === '/lower'){ // 소문자로 요청했을 경우
response.end(body.toLowerCase()); // 바디에 소문자로 전환해 보낸다.
} else { // 그 외는 에러를 담아 보낸다.
response.writeHead(404, defaultCorsHeader);
response.end();
}
})
}
각 'data' 이벤트에서 발생시킨 chunk는 Buffer이다.
chunk는 문자열 데이터이기 때문에 'data'를 배열에 담고
end 이벤트에서 이어붙인 다음 문자열로 만드는 것이 가장 좋다.
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
// 여기서 `body`에 전체 요청 바디가 문자열로 담겨있습니다.
});
(응답 헤더작성) response 객체의 메소드 : writeHead(statusCode, object)
(응답 바디작성) response 객체의 메소드 : end([data], [encoding])
전체 코드
const http = require('http');
const PORT = 4999;
const ip = 'localhost';
const server = http.createServer((request, response) => {
if (request.method === 'OPTIONS'){
response.writeHead(200, defaultCorsHeader);
response.end('hello mini-server sprints');
};
if (request.method === 'POST'){
let body = [];
request.on('data', (chunk)=>{
body.push(chunk)
}).on('end', ()=>{
body = Buffer.concat(body).toString();
response.writeHead(201, defaultCorsHeader);
if (request.url === '/upper'){
response.end(body.toUpperCase());
} else if (request.url === '/lower'){
response.end(body.toLowerCase());
} else {
response.writeHead(404, defaultCorsHeader);
response.end();
}
})
}
});
server.listen(PORT, ip, () => {
console.log(`http server listen on ${ip}:${PORT}`);
});