CORS
가 생긴이유예전엔 서버가 클라이언트라는 파일을 가지고 있었고, 유저가 서버에게 요청을 하면 서버가 클라이언트를 전달하는 방식이었음. Same Origin, 즉 서버에서 준 Client 였기 때문에 서버는 의심을 하지 않고 주고받음
그러나 최근 Web App 이 고도화되면서, 여러 곳에 있는 리소스를 활용해야 할 이유가 생겼음. 그래서 이전처럼 Same Origin 이 아니라, Cross Origin 상황이 생김. CORS 는 위와 같은 상황인 Cross Origin Resource Sharing
의 약자로, 다른 Origin 에서 Resource 를 요청하기 위해 필요한 것.
일단 기본적으로 브라우저에서 Corss Domain Request 는 기본적으로 제한되어있음. 이유는 보안상의 이유. 그러나 고도화 된 앱의 기술수준을 만족하기 위해서 이는 필요한 기능이었고 개선을 거쳐 현재는 서버가 허용한 범위 내에서는 Cross Origin 요청을 허용 할 수 있음.
Header
파일의 설정이를 가능케 하는 것은 Header
파일에서의 설정인데, 이 CORS 를 허용하게끔 하는 헤더의 대략적인 코드와 주석을 적어보자면 다음과 같음
const defaultCorsHeader = {
'access-control-allow-origin': '*',
//wild card(*) 를 이용해, 모든 도메인에서의 CORS 요청을 허용하겠다는 의미
'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
//허용 가능한 method 는 'GET, POST, PUT, DELETE, OPTIONS' 로 제한함
'access-control-allow-headers': 'content-type, accept',
//헤더에는 'content-type, 그리고 accept' 까지만 쓸 수 있으며
'access-control-max-age': 10 //sec
//preflight 요청은 10초까지만 허용가능하다
};
그리고, 이 CORS 요청과 서버와의 통신은 이런 순서대로 이뤄진다
OPTION
메서드를 통해 서버에게 preflight request 를 보내 CORS ORIGIN 에 대한 정보를 확인한다. POST
등의 요청을 보내면서(서버가 허용한 메서드여야 가능하) 서버와 통신을 계속한다. 2. SPEC 에 대한 상세 설명
HTTP Protocol
을 통해 통신해서 API 를 제공하는 주체GET
과 POST
에 따라 분기하기Object
나 Array
를 통해 임시로 받아서 처리해보자fs module
을 통해 저장하는 방법이 있긴 함 (기본적으론 Database 를 통해서 하지만...)require(), exports, module.exports 공식문서로 이해하기
이해하기 쉽게 요약한 글
node.js 의 export shortcuts 문서
node.js 의 require 문서
예제 코드
request-handler.js
파일에서 const 로 선언한 함수 requestHandler
를 export 하려면?
const requestHanlder = function(req, res) {
//code...
}
module.export = requestHanlder;
그리고 그것을 불러오려면?
const requestHanlder = require('/request-handler.js');
그 외에도 JS의 export
가 있는데, node.js 환경에서는 module.export
만이 사용이 가능하다. 그래서 module.export
를 사용하여 requestHandler
를 내보냈다.
routing 의 정의 : 서버로부터 들어오는 요청들을 조건에 따라 나누는, 즉 분기하는 것
일단 오늘은 /messages
라는 URL 만을 사용해서 데이터를 주고받을 것이라, URL 을 기준으로 먼저 routing 을 했다. 그리고 그 다음엔 method 들을 기준으로 routing 을 처리하였다.
// /messages 로 날아오는 것들을 먼저 route 한다
if (request.url === "/messages") {
// 그 다음, method 기준으로 분기를 해주자
if (request.method === "POST") {
let data = '';
request.on('data', (chunk) => {
data += chunk;
});
request.on('end', () => {
data = data.toString(); // 일단은 buffer -> string 으로 바꿔줌
console.log(data);
container.results.push(JSON.parse(data));
response.writeHead(201, headers);
response.end(data); // 그리고 json -> object 로 바꿔줌
})
}
else if (request.method === "GET") {
response.writeHead(200, headers);
// console.log(msgDatas)
// console.log(msgDatas[0])
response.end(JSON.stringify(container));
}
//OPTIONS 로 preflight request 를 날리는 경우는 header 와 status code 만 response
else if (request.method === "OPTIONS") {
response.writeHead(201, headers);
response.end();
}
// endpoint가 /messages 가 아닌 경우는 모두 404 status code 를 response
} else {
response.writeHead(404, headers);
response.end();
}
// cors 관련 세팅을 잡아준 header
const headers = {
"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 // Seconds.
};
How to handle the POST request body in Node.js without using a framework
오늘 하는 것은 http
module 를 사용한 서버 구현
on
은 eventEmitter
, event 가 오면 작동을 시작하라! 라는 기능이라고 볼수 있다.
→ 요청에 따른 응답을 주는 HTTP 의 기본적인 형태와 일맥상통하다.
문서를 '반드시' 위에부터 꼭 정독할 필요는 없다, 실행되는 예제(working example)들을 복붙하고 조금씩 수정해가고, 그 때 문서를 찾아보며 능동적으로 이해하는 게 좋다. 그러면서 test case 들을 통과시키면서 이해하면 Best.
request
의 error, 그리고 response
의 error 를 둘 다 처리해주면 좋다.
response.end()
는 응답을 마무리해준다는 걸 명시해주는 객체이다.
content-type
: 적절한 MIME type
을 넣어주는 header
의 일부분
**header
를 넣는 방법은 두 개**
setHeader
: 하나하나씩 key-value 쌍으로 넣는다writeHead
: 객체형태까지 한 번에 넣어준다, 대신 여기에 statusCode 도 같이 넣어준다writeHead(statusCode, headerObj)
와 같은 식으로 사용가능serverResponse
를 참고하면 된다.**routing
: 요청에 따른 분기를 의미하며, 크게 두 개를 기준으로 라우팅을 해준다.**
request.url
을 기준으로 나눠줄 때, /url 과 url 은 완전히 다르다는 점OPTION
method 도 잡아줘야 한다→ 날아오는 request 들을 를 이런 기준으로 나누어주면 된다. (조건문을 사용한다)
**Stream**
데이터를 한 번에 받지 않고 나누어 받는 일련의 단위를 의미한다. 그 일련의 단위만큼 잠시 데이터를 담아놓는 RAM 에 할당된 임시 공간을 Buffer
라고 한다.
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
//body 배열에 담긴 buffer 를 toString() 메서드를 이용해 변환한다
//아니면, 공백 문자열에 + 연산자를 통해 buffer 의 하나하나의 조각들(chunk)를 합쳐도 된다
}
❓궁금한 점, 왜 .on 을 또 body 에 chunk 들을 다 담은다음 붙여주는 것일까?
→ 요청을 다 받고 요청이 끝나면 end 를 보내주는 걸 명시하기 위해 on('end')
를 사용한다.
**CORS
setting with header
file**
header 파일에 CORS 를 허용하는 정보를 기입하여 CORS 가 가능하게끔 해준다.
OPTIONS
메소드도 설정해 줘야한다, 왜냐면 계속 header 정보가 맞는지 아닌지 확인해봐야 하기 때문에.
네트워크 탭에서 All
부분에 method name 이fetch
가 아닌 경우는 OPTIONS
method 라고 생각하면 된다.
여튼, 네트워크 탭에서 요청을 보았을 때 내 client 의 localhost 뒤의 port number 와 내가 구축한 server 의 port number 가 다른 상황이기 때문에 cross origin resource sharing 설정을 잡아주어야 한다는 점이다.
네트워크 탭에서 내가 어떤 요청을 보내고 어떤 응답을 보냈는지 반드시 확인해야 한다!
JSON.stringfy()
를 안 해주면 객체가 풀로 나오는게 아니라 [Object, Object]
같이 뜬다.
[ERR_INVALID_ARG_TYPE] 오류
HTTP 통신에서 서로 주고받는 데이터의 타입은string
혹은 buffer
만 가능하다. Object
를 그대로 전달해선 안 된다. 이를 JSON.stringify(Object)
등을 통해 string
화를 시켜주고, 받을 땐 이 JSON
을 parsing 해서 받아주면 된다.
error code
중에 201과 200 의 차이점
OK
Created
POST
나 일부 PUT
요청 이후에 사용하는 것이 적절하다