1. 웹서버 생성
yarn add express
//src/index.js
const http = require('http');
const express = require('express');
//익스프레스 서버 객체
const app = express();
//웹 서버의 port속성 설정
app.set('port', 3000);
http.createServer(app).listen(app.get('port'), ()=>{
console.log('express server starts : ' + app.get('port'));
});
express server object의 메소드
- set(name, value) : 서버 설정을 위한 속성 지정
- get(name) : 지정한 속성 반환
- use([path], function) : 미들웨어함수 등록
- get([path], function) : 특정 패스로 요청된 정보 처리
2. 미들웨어
2-1. 미들웨어등록
//src/index.js
const http = require('http');
const express = require('express');
//익스프레스 서버 객체
const app = express();
//미들웨어 등록
app.use((req,res,next)=>{
console.log('first middleware');
//req객체에 user속성을 추가하고 문자열 할당
req.user = 'mike';
//다음 미들웨어 호출
next();
});
app.use('/',(req,res,next)=>{
console.log('second middleware');
res.writeHead('200', {'content-type':'text/html;charset=utf-8'});
res.write('<p>express server 응답 결과 : ' + req.user + '</p>');
res.end();
})
//웹 서버의 port속성 설정
app.set('port', 3000);
http.createServer(app).listen(app.get('port'), ()=>{
console.log('express server starts : ' + app.get('port'));
});
- app.use파라미터로 등록된 함수가 하나의 미들웨어
- 미들웨어 함수는 req, res, next 객체를 파라미터로 받음
- req : 요청객체
- res : 응답객체
- next() : 현재처리중인 미들웨어의 다음 미들웨어를 호출하는 함수
2-2. 응답객체 메소드
- writeHead(statusCode, statusMessage, headers)
- write(chunk, encoding, callback) : 여러번 작성가능
- end(data, encoding, callback)
+
express에서 추가로 사용 가능한 메소드
- send() : 클라이언트에 모든 종류의 응답데이터를 보낸다 (html, buffer객체, json객체, json배열 등등 -> 만능메서드)
//app.use('/',(req,res,next)=>{
// res.writeHead('200', {content-type':'text/html;charset=utf-8'});
// res.write("<p>server response</p>");
// res.end();
//});
app.use('/',(req,res,next)=>{
res.send('<p>express server response</p>');
});
- status(code) : http 상태코드 반환 -> send()메소드를 연속으로 호출해야 전송
- sendStatus(code) = status(code).send();
app.use('/',(req,res,next)=>{
res.status(404).send();
})
//app.use('/',(req,res,next)=>{
// res.sendStatus(404);
//})
- redirect([status], path) : 웹페이지 경로를 강제로 이동
app.use('/',(req,res,next)=>{
//디폴트 상태값 : 302
res.redirect(302,'http://www.naver.com');
});
2-3. 요청객체의 속성
- req.query : 클라이언트에서 get방식으로 전송한 데이터(querystring) 확인, url query로 전송한 데이터(querystring) 확인
- req.body : 클라이언트에서 post방식으로 전송한 데이터(querystring) 확인, (body-parser 외장모듈 필요)
- req.params : 라우트 파라미터를 확인할 수 있는 객체, 이 객체의 속성을 "토큰"이라고 한다.
- header(name) : header를 확인
2-4. static middleware
: 특정 폴더의 파일들을 특정패스로 접근할 수 있도록 만들어준다.
yarn add server-static
public 디렉토리를 만들고 그 안에 index.html파일을 만든다.
app.use('/public', static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
-> http://localhost:3000/public/index.html로 index.html 접근 가능
2-5. body-parser middleware
: 클라이언트가 post방식으로 요청할 때 본문 영역에 들어 있는 요청파라미터(querystring)들을 파싱하여
요청객체(req)의 "body" 속성에 넣어준다. ex) req.body.key
<!-- public/index.htrml -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>test page</h1>
<!-- post방식 -->
<form method="post">
<table>
<tr>
<td><label>아이디</label></td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td><label>비밀번호</label></td>
<td><input type="password" name="pw"></td>
</tr>
</table>
<input type="submit" value="submit" name="">
</form>
</body>
</html>
//src/index.js
const http = require('http');
const express = require('express');
const static = require('serve-static');
const path = require('path');
const bodyParser = require('body-parser');
//익스프레스 서버 객체
const app = express();
app.set('port', 3000);
//미들웨어 등록
//body-parser를 사용해 application/x-www-from-urlencoded 파싱
app.use(bodyParser.urlencoded({extended:false}));
//body-parser를 사용해 application/json 파싱
app.use(bodyParser.json());
app.use('/public', static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
app.use((req,res)=>{
const paramId = req.body.id;
const paramPw = req.body.pw;
res.send("id : " + paramId + "<br>" + "pw : " + paramPw);
// res.writeHead('200', {'content-type':'text/html;charset=utf-8'});
// res.write("<h1>response</h1>");
// res.write("<p>id : " + paramId + "</p>");
// res.write("<p>pw : " + paramPw + "</p>");
// res.end();
})
//웹 서버의 port속성 설정
http.createServer(app).listen(app.get('port'), ()=>{
console.log('express server starts : ' + app.get('port'));
});
3. 라우팅
: 다른주소로 요청이 들어올 때, 다른 작업을 처리할수 있도록 라우터 사용 -> 사용자가 요청한 기능이 무엇인지 패스를 기준으로 구별
3-1. 라우터 설정 및 등록
<!-- public/index.htrml -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- GET방식 -->
<h1>GET</h1>
<form method="GET" action="../src/index.js">
<table>
<tr>
<td><label>아이디</label></td>
<td><input type="text" name="gid"></td>
</tr>
<tr>
<td><label>비밀번호</label></td>
<td><input type="password" name="gpw"></td>
</tr>
</table>
<input type="submit" value="submit" name="">
</form>
<hr>
<!-- POST방식 -->
<h1>POST</h1>
<form method="POST">
<table>
<tr>
<td><label>아이디</label></td>
<td><input type="text" name="pid"></td>
</tr>
<tr>
<td><label>비밀번호</label></td>
<td><input type="password" name="ppw"></td>
</tr>
</table>
<input type="submit" value="submit" name="">
</form>
</body>
</html>
// src/index.js
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
//익스프레스 서버 객체
const app = express();
//라우터 객체 참조
const router = express.Router();
//포트설정
app.set('port', 3000);
//미들웨어 등
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// static 미들웨어
app.use('/public', express.static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
//라우팅 함수 설정
router.get('/',(req, res) => {
console.log("/ get방식으로 요청들어옴");
res.send("<p>HOME</p>");
});
router.get('/src/index.js',(req, res) => {
console.log("/src/index.js 에서 get방식으로 요청들어옴");
const paramgId = req.query.gid;
const paramgPw = req.query.gpw;
res.writeHead('200', { 'content-type': 'text/html;charset=utf-8' });
res.write("<h1>GET</h1>");
res.write("<p>id : " + paramgId + "</p>");
res.write("<p>pw : " + paramgPw + "</p>");
res.end();
});
router.post('/public/index.html',(req, res) => {
console.log("/public/index.html 에서 post방식으로 요청들어옴");
const paramId = req.body.pid;
const paramPw = req.body.ppw;
res.writeHead('200', { 'content-type': 'text/html;charset=utf-8' });
res.write("<h1>POST</h1>");
res.write("<p>id : " + paramId + "</p>");
res.write("<p>pw : " + paramPw + "</p>");
res.end();
});
//라우터 등록
app.use('/', router);
//웹 서버의 port속성 설정
http.createServer(app).listen(app.get('port'), () => {
console.log('express server starts : ' + app.get('port'));
});
- 라우팅 함수 설정 (19~43행)
- GET 방식으로 request 발생시 req.query 객체에서 속성조회가능
- POST 방식으로 request 발생시 req.body 객체에서 속성조회가능 (body-parser 미들웨어 필수)
- 라우터 등록 (46행)
3-2. 클라이언트->서버로 데이터(querystring) 전송 방법 : URL query와 라우트 파라미터, form태그
- URL query(url parameter) : url 뒤에 ?를 붙이고 querysting을 추가하여 보내면 자동으로 객체 형태로 파싱되어 req.query에서 확인 가능
- 라우트파라미터 : 라우트경로 설정 시 맨뒤에 /:parameter? 와 같은 형식으로 라우터 경로 설정하면 req.params 객체에서 속성(토큰)으로 확인 가능. 이 속성을 '토큰'이라고 부른다.
- form 태그 : method속성으로 데이터를 보내는 방식을 설정 가능 (get, post, etc)
=> get 방식으로 보낸 데이터는 req.query, post방식으로 보낸 데이터는 req.body에서 확인 가능
// src/index.js
//...
router.get('/src/index.js/:name?',(req, res) => {
console.log("/src/index.js 에서 get방식으로 요청들어옴");
const {name} = req.params;
const paramgId = req.query.gid;
const paramgPw = req.query.gpw;
res.writeHead('200', { 'content-type': 'text/html;charset=utf-8' });
res.write("<h1>GET</h1>");
res.write("<p>id : " + paramgId + "</p>");
res.write("<p>pw : " + paramgPw + "</p>");
res.write("<p>name : " + name + "</p>");
res.end();
});
/...
=> url : http://localhost:3000/src/index.js/John?gid=123&gpw=456
=> 결과 : id : 123 pw = 456 name : John (John은 토큰)
3-3. request path를 router 객체에 설정시 사용하는 메소드
- get('request path', callback) : get 방식으로 request path 에서 요청이 발생이 콜백함수 실행
- post('request path', callback) : post 방식으로 request path 에서 요청이 발생이 콜백함수 실행
- put('request path', callback) : put 방식으로 request path 에서 요청이 발생이 콜백함수 실행
- delete('request path', callback) : delete 방식으로 request path 에서 요청이 발생이 콜백함수 실행
- patch('request path', callback) : patch 방식으로 request path 에서 요청이 발생이 콜백함수 실행펭
- all('request path', callback) : 모든방식으로 request path 에서 요청이 발생이 콜백함수 실행 - > 페이지 오류 응답 처리하는데 사용
// src/index.js
//...
router.all('*', (req,res)=>{
res.status(404).send("<h1>404 ERROR - page not found</h1>");
});
/...
3-4. 라우트 모듈화
- 모듈화 전
// src/index.js
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
//익스프레스 서버 객체
const app = express();
//라우터 객체 참조
const router = express.Router();
//포트설정
app.set('port', 3000);
//미들웨어 등
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// static 미들웨어
app.use('/public', express.static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
//라우팅 함수
router.get('/',(req, res) => {
console.log("/ get방식으로 요청들어옴");
res.send("<h1>HOME</h1>");
});
router.get('/about/:name?', (req,res)=>{
const {name} = req.params;
if(name){
res.send(`${name} 소개`);
}else{
res.send("소게");
}
});
router.get('/posts',(req,res)=>{
const {id} = req.query;
if(id){
res.send(`포스트 #${id}`);
}else{
res.send("포스트id 없음");
}
});
router.all('*', (req,res)=>{
res.status(404).send("<h1>404 ERROR - page not found</h1>");
});
//라우터 등록
app.use('/', router);
//웹 서버의 port속성 설정
http.createServer(app)
.listen(app.get('port'), () => {
console.log('express server starts : ' + app.get('port'));
});
- 모듈화 후
// src/index.js
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
//익스프레스 서버 객체
const app = express();
//라우터 설정
const router = require('./router');
//포트설정
app.set('port', 3000);
//미들웨어 등
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// static 미들웨어
app.use('/public', express.static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
//라우터 등록
app.use('/', router);
//웹 서버의 port속성 설정
http.createServer(app)
.listen(app.get('port'), () => {
console.log('express server starts : ' + app.get('port'));
});
//라우트 모듈화
// src/router/index.js
const express = require('express');
const router = express.Router();
router.get('/',(req, res) => {
console.log("/ get방식으로 요청들어옴");
res.send("<h1>HOME</h1>");
});
router.get('/about/:name?', (req,res)=>{
const {name} = req.params;
if(name){
res.send(`${name} 소개`);
}else{
res.send("소게");
}
});
router.get('/posts',(req,res)=>{
const {id} = req.query;
if(id){
res.send(`포스트 #${id}`);
}else{
res.send("포스트id 없음");
}
});
router.all('*', (req,res)=>{
res.status(404).send("<h1>404 ERROR - page not found</h1>");
});
module.exports = router;
- posts 라우트
//src/api/posts/index.js
const express = require('express');
const posts = express.Router();
const printInfo = (req,res)=> {
res.send(req.body = {
method:req.method,
path : req.originalUrl,
params: req.params
})
};
posts.get('/', printInfo);
posts.post('/', printInfo);
posts.get('/:id', printInfo);
posts.delete('/:id', printInfo);
posts.put('/:id', printInfo);
posts.patch('/:id', printInfo);
module.exports = posts;
//src/api
const express = require('express');
const api = express.Router();
const posts = require('./posts');
api.use('/posts', posts);
module.exports = api;
//src/index.js
const http = require('http');
const express = require('express');
// const static = require('serve-static');
// const path = require('path');
const bodyParser = require('body-parser');
//익스프레스 서버 객체
const app = express();
//라우터 설정
const api = require('./api');
//포트설정
app.set('port', 3000);
//미들웨어 등
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// static 미들웨어
app.use('/public', express.static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
//라우터 등록
app.use('/api', api);
//웹 서버의 port속성 설정
http.createServer(app)
.listen(app.get('port'), () => {
console.log('express server starts : ' + app.get('port'));
});
3-5. 컨트롤러 파일
- 컨트롤러 : 라우트 처리 함수만 모아놓은 파일
- 컨트롤러에서는 백엔드 기능을 구현
//src/api/posts/posts.ctrl.js
//컨트롤러 파일
let postId = 1; // id 초깃값
const posts = [{ id: 1, title: '제목', body: '내용' }];
//목록조회 GET /api/posts
exports.list = (req, res) => {
res.send(posts);
};
//특정포스트 조회 GET /api/posts/:id
exports.read = (req, res) => {
const { id } = req.params;
const post = posts.find(p => p.id.toString() === id);
//포스트 없으면 오류 반환
if (!post) {
res.status(404).send("포스트없음");
return;
}
res.send(post);
};
//포스트 작성 POST /api/posts
exports.write = (req, res) => {
const { title, body } = req.body;
postId += 1;
const post = { id: postId, title, body };
posts.push(post);
res.send(post);
};
//특정포스트 제거 DELETE /api/posts/:id
exports.remove = (req, res) => {
const { id } = req.params;
const index = posts.findIndex(p => p.id.toString() === id);
if (index === -1) {
res.status(404).send("포스트없음");
return;
}
posts.splice(index, 1);
res.status(204).send("콘텐츠 없음, no content");
};
// 포스트 수정 PUT /api/posts/:id
//put 메소드는 전체 포스트 정보를 입력하여 데이터를 통째로 교체할 때 사용
exports.replace = (req, res) => {
const { id } = req.params;
const index = posts.findIndex(p => p.id.toString() === id);
if (index === -1) {
res.status(404).send("포스트없음");
return;
}
posts[index] = {
id,
...req.body
};
res.send(posts[index]);
};
//포스트 수정 PATCH /api/posts/:id
exports.update = (req, res) => {
const { id } = req.params;
const index = posts.findIndex(p => p.id.toString() === id);
if (index === -1) {
res.status(404).send("포스트없음");
return;
}
posts[index] = {
...posts[index],
...req.body
}
res.send(posts[index]);
};
//src/api/posts/index.js
// posts 라우터
const express = require('express');
const posts = express.Router();
const postsCtrl = require('./posts.ctrl');
posts.get('/', postsCtrl.list);
posts.post('/', postsCtrl.write);
posts.get('/:id', postsCtrl.read);
posts.delete('/:id', postsCtrl.remove);
posts.put('/:id', postsCtrl.replace);
posts.patch('/:id', postsCtrl.update);
module.exports = posts;
//src/api/index.js
//라우트 모듈화
const express = require('express');
const api = express.Router();
const posts = require('./posts');
api.use('/posts', posts);
module.exports = api;
//src/index.js
// 백엔드 프로그래밍
const http = require('http');
const express = require('express');
// const static = require('serve-static');
// const path = require('path');
const bodyParser = require('body-parser');
//익스프레스 서버 객체
const app = express();
//라우터 설정
const api = require('./api');
//포트설정
app.set('port', 3000);
//미들웨어 등
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// static 미들웨어
app.use('/public', express.static("/home/yongmin/Desktop/React/blog/blog-backend/public"));
//라우터 등록
app.use('/api', api);
//웹 서버의 port속성 설정
http.createServer(app)
.listen(app.get('port'), () => {
console.log('express server starts : ' + app.get('port'));
});