3주간의 블로깅 챌린지 마지막 날이다.
그동안 가장 어려웠고, 언젠간 꼭 써야지 했던 웹 서버에 대해서 써보려 한다.
1. (복습) HTTP 요청과 응답
A. GET
GET 메서드는 URI를 통해 서버에서 원하는 정보를 요청하는 메서드이다.
URI는 서버에 저장되어 있는 데이터에 접근하는 방식이었다.
이 경우, google.com 이라는 서버의 search 디렉토리에서 RHCP라는 쿼리를 가진 요소에 접근하는 URI이다.
GET 메서드는 단순히 데이터 조회만 할 수 있으며, 서버에 저장된 데이터를 변경할 수는 없다.
GET 메서드는 데이터에 영향을 주지 않기 때문에 따로 본문(Body)을 작성하지 않아도 된다.
B. POST
POST 메서드는 HTTP 메시지 본문을 통해 데이터를 전송하는 메서드이다.
GET 메서드와는 달리, POST 메서드는 서버에 저장된 데이터를 수정할 수 있다(ex.회원가입, 예약 등)
POST 메시지는 본문을 가지고 있다. 따라서 클라이언트가 전송하고 싶은 데이터를 본문에 담아 전송하면 서버는 수신한 데이터를 저장한다. 그렇기 때문에 POST 메서드는 서버에 영향을 줄 수 있다.
C. Response
클라이언트로부터 요청을 받으면, 서버는 요청에 맞는 작업을 수행한 뒤 요청을 보내주어야 한다.
GET과 POST는 똑같이 데이터를 전송하지만 요구하는 데이터가 다를 수 있기 때문에, 응답 메시지로 응답의 종류를 구분한다.
응답 메시지 역시 본문에 클라이언트가 요청한 데이터를 담아 보내며, HTML이나 JSON 데이터를 송신한다.
2. Web Server 구축
HTTP 메시지 전송과 응답을 알아 보았으니, 수업시간에 진행했던 대소문자 변환 과제를 통해 웹 서버에서 어떻게 메시지가 전달되는지 확인해 보도록 하자
이미 완료한 과제이기 때문에, 과제 내용보다는 어떤 방식으로 작동되고, 어떻게 과제 코드에 요청과 응답이 전달되는지를 알아보도록 하겠다.
우선 Node.js로 웹 서버를 만들어준다.
const http = require('http');
const PORT = 4999;
const ip = 'localhost';
const server = http.createServer((request, response) => {
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
if (request.method === 'POST' && request.url === '/upper') {
response.writeHead(200, defaultCorsHeader);
response.end(body.toUpperCase());
} else if (request.method === 'POST' && request.url === '/lower') {
response.writeHead(200, defaultCorsHeader);
response.end(body.toLowerCase());
} else if (request.method === 'OPTIONS') {
response.writeHead(200, defaultCorsHeader)
response.end()
}else {
response.writeHead(404, defaultCorsHeader)
response.end('bad request')
}
});
});
server.listen(PORT, ip, () => {
console.log(`서버 실행 / ${ip}:${PORT}`);
});
//CORS 에러 방지
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
};
코드를 하나하나 찬찬히 뜯어 살펴보자
//HTTP 모듈을 불러온다
const http = require('http');
//포트와 IP를 설정
const PORT = 4999;
const ip = 'localhost';
});
먼저 서버 구축이다. Node.js의 HTTP 모듈을 이용해 서버를 구축할 것이므로 모듈을 불러오고, 포트와 ip를 설정해준다. 여기까지는 기본
//서버를 만든다
const server = http.createServer((request, response) => {
//이때, 서버는 받는 요청과 보낼 응답을 매개변수로 받는다
//받은 url의 메서드, 주소, 헤더를 가져옴
const {method, url, headers} = request
//요청으로 온 문자열을 하나씩 받아 하나의 문자열로 합침
let body = [];
//on 메서드는 지정된 이벤트를 통합해 한번에 처리
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
//받아온 문자열 = body
body = Buffer.concat(body).toString();
//요청의 method와 url에 따라 다른 응답을 내보냄
if (request.method === 'POST' && request.url === '/upper') {
//writeHead는 헤더 정보를 내보낸다.
//첫번째 인자로는 상태 코드, 두번째 인자로는 헤더 정보를 입력한다
response.writeHead(200, defaultCorsHeader);
//end는 최종적인 응답(response)을 내보낸다
//인자로는 응답으로는 본문(body)에 들어갈 메시지를 입력한다
//response.write(내보낼 메시지)를 통해 메시지를 입력하고, end()로 내보낼수도 있다
response.end(body.toUpperCase());
} else if (request.method === 'POST' && request.url === '/lower') {
response.writeHead(200, defaultCorsHeader);
response.end(body.toLowerCase());
} else if (request.method === 'OPTIONS') {
response.writeHead(200, defaultCorsHeader)
response.end()
}else {
response.writeHead(404, defaultCorsHeader)
response.end('bad request')
}
});
createServer 메서드로 새로운 서버를 만들어준다.
이때 서버는 요청을 받고, 요청에 따른 응답을 보내주어야 하기 때문에 request, response를 매개변수로 가져야 한다.
createServer 메서드 안에서는 request를 받았을 때, 이 request에 따른 response를 어떻게 보내줄지에 대해 구현하면 된다.
server.listen(PORT, ip, () => {
console.log(`http server listen on ${ip}:${PORT}`);
});
listen 메서드는 서버를 실행시키고, 대기 상태로 만든다. 이 상태에서 request를 받고, response를 내보낼 수 있다.
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
};
writeHead에 들어갈 헤더 정보이다. CORS 에러를 방지하기 위해 모든 출처에서 리소스 공유를 가능하게 설정해 주었다.
이제 서버를 구축했으니 어떻게 서버가 동작하는지 확인해보자
class App {
init() {
document
.querySelector('#to-upper-case')
.addEventListener('click', this.toUpperCase.bind(this));
document
.querySelector('#to-lower-case')
.addEventListener('click', this.toLowerCase.bind(this));
}
post(path, body) {
fetch(`http://localhost:4999/${path}`, {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(res => {
this.render(res);
});
}
toLowerCase() {
const text = document.querySelector('.input-text').value;
this.post('lower', text);
}
toUpperCase() {
const text = document.querySelector('.input-text').value;
this.post('upper', text);
}
render(response) {
const resultWrapper = document.querySelector('#response-wrapper');
document.querySelector('.input-text').value = '';
resultWrapper.innerHTML = response;
}
}
const app = new App();
app.init();
App이라는 클래스를 만들고, 메서드를 통해 서버에 요청을 보내는 방법을 사용하였다.
다른 부분은 제외하고 서버에 관여하는 부분만 하나하나 뜯어가며 살펴보자
//POST 메서드 구현
post(path, body) {
//우리가 만든 서버에 데이터를 추가한다
fetch(`http://localhost:4999/${path}`, {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json'
}
})
//추가한 데이터에 대한 응답을 받아 출력한다
.then(res => res.json())
.then(res => {
this.render(res);
});
}
post 메서드에는 데이터를 저장할 서버의 디렉토리인 path와 전달할 내용인 body를 매개변수로 준다.
fetch를 통해 localhost:4999 서버 /path 디렉토리에 두번째 전달인자인 객체를 추가하는 것이다.
추가된 데이터는 서버에 구현된 변환 알고리즘을 따라 변환된 뒤, 응답으로 내보내진다.
이 응답은 첫번째 then 메서드 내의 res에 저장되고, 이 res의 형변환을 거친 후 render 메서드에 넣어 결과 화면을 출력하는 것이다.
toLowerCase() {
const text = document.querySelector('.input-text').value;
this.post('lower', text);
}
toUpperCase() {
const text = document.querySelector('.input-text').value;
this.post('upper', text);
}
render(response) {
const resultWrapper = document.querySelector('#response-wrapper');
document.querySelector('.input-text').value = '';
resultWrapper.innerHTML = response;
}
위의 두 메서드는 위에서 만든 post에 .path와 입력한 text를 추가해주는 메서드이고, render 메서드는 매개변수를 받아 출력 화면에 출력하는 메서드이다.
위 과정을 그림으로 나타내 보자
이번 블로깅을 통해 정말 막막했던 웹 서버에 대해 조금이나마 더 알게 된 것 같다.
Section 2 Solo Project를 아직 완벽하게 구현해 내지 못했는데, 오늘의 공부를 바탕으로 다시 만들어봐야겠다.
'Frontend Study' 카테고리의 다른 글
[FE_Bootcamp] 57일차_토큰 (0) | 2023.05.03 |
---|---|
[FE_Bootcamp] 56일차_쿠키와 세션 (0) | 2023.05.02 |
[FE_Bootcamp] 55일차_네트워크 (0) | 2023.05.01 |
[FE_Bootcamp] 53일차_Web 접근성 (0) | 2023.04.28 |
[FE_Bootcamp] 52일차_Web 표준 (1) | 2023.04.28 |