const http = require('http');
const server = http.createServer((req, res) => {
res.write('<h1>hello node</h1>');
res.write('<h2>hello node</h2>');
res.write('<h3>hello node</h3>');
})
.listen(8080);
server.on('listening', () => {
console.log('8080포트에서 서버 대기 중입니다.');
});
server.on('error', () => {
console.log(error);
});
localhost8080에 들어가면 hello node 가 나옴!
localhost는 컴퓨터 내부 주소로 외부에서는 접근이 안됨..!
const http = require('http');
const fs = require('fs').promises;
const server = http.createServer(async(req, res) => {
try {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
const data = await fs.readFile('./chap4/server2.html');
res.end(data);
}
catch (error) {
console.log(error);
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(error.message);
}
})
.listen(8080);
server.on('listening', () => {
console.log('8080포트에서 서버 대기 중입니다.');
});
server.on('error', (error) => {
console.log(error);
});
서버에 요청을 보낼 때 주소를 통해 요청의 내용을 표현
-> 서버가 이해하기 쉬운 주소로 보내는게 좋음
REST API: 주소를 정하는 규칙
RESTful: REST API를 사용한 주소 체계를 이용하는 서버
GET: 서버 자원을 가져와야 할 때
POST: 서버에 자원을 새로 등록하고자 할때
PUT: 서버의 자원을 요청에 들어잇는 자원으로 치환하려 할때(전체수정)
PATCH: 서버 자원의 일부만 수정하고자 할때(일부수정)
DELETE: 서버의 자원을 삭제하고자 할때
이 서버의 설명
writeHead : http 서버에서 응답헤더를 설정
res.end()로 본문을 전송하여 응답 완료const http = require('http');
const fs = require('fs').promises;
const path = require('path');
const users = {}; // 데이터 저장용
//서버 생성, req: request, res: respond
http.createServer(async (req, res) => {
try {
if (req.method === 'GET') {
//GET /: restFront.html 파일을 읽어와 응답
//200 응답코드와 함께 html 반환
if (req.url === '/') {
const data = await fs.readFile(path.join(__dirname, 'restFront.html'));
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
//200,201 -> 성공적으로 요청에 응답
//404 -> 요청에 응답 실패 NOT FOUND
return res.end(data);
}
//GET /about: about.html을 읽어와 응답
else if (req.url === '/about') {
const data = await fs.readFile(path.join(__dirname, 'about.html'));
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(data);
}
//GET/ users: users 객체를 JSON 형식으로 응답
else if (req.url === '/users') {
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
return res.end(JSON.stringify(users));
}
// /도 /about도 /users도 아니면
try {
const data = await fs.readFile(path.join(__dirname, req.url));
return res.end(data);
} catch (err) {
// 주소에 해당하는 라우트를 못 찾았다는 404 Not Found error 발생
}
}
//POST 요청 처리: 사용차 추가
else if (req.method === 'POST') {
// POST /user
if (req.url === '/user') {
let body = '';
// 데이터를 스트림 형태로 받아 body 변수에 저장
req.on('data', (data) => {
body += data;
});
// 요청의 body를 다 받은 후 실행됨
// 받은 JSON 데이터를 파싱하여 사용자 객체에 추가
return req.on('end', () => {
console.log('POST 본문(Body):', body);
const { name } = JSON.parse(body);
const id = Date.now();
users[id] = name;
res.writeHead(201, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('등록 성공');
});
}
}
//PUT /user:id : 해당 사용자의 정보 수정
else if (req.method === 'PUT') {
if (req.url.startsWith('/user/')) {
const key = req.url.split('/')[2];
// /user/12345 같은 요청에서 12345를 추출하여 사용자의 키로 사용
// 수정할 데이터(body)를 받습니다.
let body = '';
req.on('data', (data) => {
body += data;
});
return req.on('end', () => {
console.log('PUT 본문(Body):', body);
users[key] = JSON.parse(body).name;
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
return res.end(JSON.stringify(users));
});
}
}
else if (req.method === 'DELETE') {
if (req.url.startsWith('/user/')) {
//해당 키를 가진 사용자를 삭제. 삭제 후 응답
const key = req.url.split('/')[2];
delete users[key];
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
return res.end(JSON.stringify(users));
}
}
//주소에 해당하는 라우트를 하나도 찾지 못했을 때 -> 404 NOT FOUND
res.writeHead(404);
return res.end('NOT FOUND');
} catch (err) {
console.error(err);
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
})
.listen(8082, () => {
console.log('8082번 포트에서 서버 대기 중입니다');
});
요청의 단점: 누가 요청을 보냈는지 알수가 없음
쿠키: 쿠키명=쿠키값 의 쌍
쿠키 옵션
예제코드
const http = require('http');
const fs = require('fs').promises;
const path = require('path');
//쿠키문자열을 객체{name:"value"}로 변환
const parseCookies = (cookie = '') =>
//cookie가 null/undefined라면 빈문자열
cookie //'cookie1=1234; cookie2=5678'
.split(';') //["cookie1=1234", "cookie2=5678"]
.map(v => v.split('=')) //[["cookie1", "1234"], [" cookie2", "5678"]]
.reduce((acc, [k, v]) => {
acc[k.trim()] = decodeURIComponent(v);
return acc;
//reduce() 를 이용해 {key:value}형태의 객체 생성
//k.trim(): 공백 제거
//decodeURLComponent(v): URL 인코딩된 값을 디코딩
}, {}); //결과:{cookie1: "1234"},{cookie2: "5678"}
http.createServer(async (req, res) => {
const cookies = parseCookies(req.headers.cookie); // { mycookie: 'test' }
// 주소가 /login으로 시작하는 경우(로그인버튼을 눌렀을때)
if (req.url.startsWith('/login')) {
const url = new URL(req.url, 'http://localhost:8084');
const name = url.searchParams.get('name');
const expires = new Date();
// 쿠키 유효 시간을 현재시간 + 5분으로 설정
expires.setMinutes(expires.getMinutes() + 5);
res.writeHead(302, { //302-> redirection
Location: '/',
'Set-Cookie': `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
});
res.end();
}
//주소가 / 이면서 쿠키가 있는 경우
else if (cookies.name) {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(`${cookies.name}님 안녕하세요`);
}
else {//주소가 / 이면서 쿠키가 없는 경우
try {
const data = await fs.readFile(path.join(__dirname, 'cookie2.html'));
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(data);
} catch (err) {
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
}
})
.listen(8084, () => {
console.log('8084번 포트에서 서버 대기 중입니다!');
});
쿠키의 정보는 노출되고 수정되는 위험이 있음 -> 세션 이용
세션 원리
중요한 정보는 서버에서 관리하고 클라이언트에는 세션 키만 제공
서버에 세션객체 생성 후 키(uniquelnt)를 만들어 속성명으로 이용
속성 값에 정보를 저장하고 uniquelnt를 클라이언트에 제공
6장에 더 깊게 다룰 예정
const http = require('http');
const fs = require('fs').promises;
const path = require('path');
const parseCookies = (cookie = '') =>
cookie
.split(';')
.map(v => v.split('='))
.reduce((acc, [k, v]) => {
acc[k.trim()] = decodeURIComponent(v);
return acc;
}, {});
const session = {};
http.createServer(async (req, res) => {
const cookies = parseCookies(req.headers.cookie);
if (req.url.startsWith('/login')) {
const url = new URL(req.url, 'http://localhost:8085');
const name = url.searchParams.get('name');
const expires = new Date();
expires.setMinutes(expires.getMinutes() + 5);
//**여기부터 세션**//
const uniqueInt = Date.now();
session[uniqueInt] = {
name,
expires,
};
res.writeHead(302, {
Location: '/',
'Set-Cookie': `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
});
res.end();
// 세션쿠키가 존재하고, 만료 기간이 지나지 않았다면
} else if (cookies.session && session[cookies.session].expires > new Date()) {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(`${session[cookies.session].name}님 안녕하세요`);
} else {
try {
const data = await fs.readFile(path.join(__dirname, 'cookie2.html'));
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(data);
} catch (err) {
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
}
})
.listen(8085, () => {
console.log('8085번 포트에서 서버 대기 중입니다!');
});