오늘 포스팅에서는 노드의 외장모듈인 Express
를 통해서
서버를 구축하는 과정과 기본적인 사용법을 정리합니다
npm init -y
// 지정한 디렉토리에 package.json을 생성합니다
npm install express nunjucks
// Express와 템플릿 엔진인 nunjucks를 설치합니다
이 두 코드를 터미널에 입력하면 express 설치는 자동으로 완료됩니다
- 템플릿 엔진?
템플릿 엔진은 자바스크립트를 사용해서 HTML의 렌더링을 돕는 도구입니다
웹 페이지를 렌더링하기 위한 통신 양식은 복잡하지만
거의 일정한 패턴으로 이루어집니다
템플린 엣진은 사용자에게 필요한 '템플릿'을 내장해뒀다가
간편한 사용법을 통해 꺼내 쓸 수 있도록 돕는 기능을 합니다
nunjucks
는 html을 출력하기 위한 템플릿 엔진의 일종입니다
그 밖에도 여러 템플릿 엔진이 있지만 저는 아마도 nunjucks를
계속 사용하게 될 것 같아요
+) express를 설치한 디렉토리를 git을 써서 관리하고 싶다면
node_modules 디렉토리는 .gitigonre 목록에 추가할 것!
[server.js]
const express = require("express");
// 외장모듈인 익스프레스를 불러옵니다
const app = express();
// const server = net.createServer()
const PORT = process.env.SERVER_PORT || 3000;
// 호스트(IP)는 익스프레스가 자동으로 잡아줍니다
app.listen(PORT, () => {
console.log("server start");
});
// server.listen
const app=express()
: Application 객체를 호출합니다
app 객체는express()
메소드 호출로 생성되는 익스프레스 서버 객체를 의미합니다
생성된 서버 객체(app
)는 net
모듈을 써서 서버를 만들 때 사용한
net.createServer()
와 유사한 기능을 지니고 있습니다
그리고 이 app 객체에는 listen()
을 포함한 다양한 함수들이 내장되어 있습니다
우선적으로 알아볼 것은 get()
과 use()
입니다
app.get('path', (callback))
app.post('path', (callback))
app.use('path(optional)', (callback))
// 요청과 경로(path)가 일치할 경우 콜백함수가 실행됩니다
먼저 간단히 정리하자면 app.use()
는 모든 요청을 받아들이는 반면
app.get()
은 오직 GET 요청만 처리할 수 있습니다
(고로 POST 요청에 응답할 때는 app.post()
를 사용)
서버와 연결할 때 use
메서드만 쓰는 것도 가능하지만,
라우팅 처리는 각각의 리퀘스트에 응하는 메서드와 연결하고
use
메서드는 필요한 경우 미들웨어로서 사용하도록 합시다
- 라우터?
라우터는 클라이언트의 요청 경로(path)를 확인한 뒤
이 요청을 처리할 수 있는 곳으로 기능을 전달하는 역할을 합니다
req
(요청)와 res
(응답)입니다 (순서 주의!)use
메서드의 경로를 따로 지정하지 않을 경우next
함수 인자를 끼워넣고 호출하지 않으면아래는 예제 코드입니다
app.get("/", (req, res, next) => {
//클라이언트의 GET 요청에 대응합니다
// 첫번째 인자인 "/"는 최상위 경로로 설정했음을 의미합니다
// http://localhost:3000/?name=XXX
console.log(req.query.name);
// query.name이 없으면 undefined를 출력합니다
next();
// next함수가 호출되면 아래의 콜백함수(미들웨어)를 실행합니다
},
(req, res) => {
res.send("hello world");
// 웹서버가 클라이언트에 응답할 때 보낼 메세지입니다
}
템플릿 엔진 nunjucks의 사용법을 정리합니다
템플릿 엔진은 화면에 웹페이지를 출력하기 위해 사용합니다
const nunjucks = require("nunjucks")
// 설치한 템플릿 엔진을 불러옵니다
// views 디렉토리 내부의 html 파일을 출력하기 위한 기본 세팅
// 툴 사용법이므로 암기의 영역...
app.set('view engine','html')
nunjucks.configure('views', {
express:app
})
// 정적(static) 파일 연결을 위한 미들웨어
// public 디렉토리 안의 내용을 로드합니다 (next함수는 자동실행)
app.use(express.static("public"))
익스프레스에는 정적 파일을 연결해주는 static
이라는 메서드가 내장되어있습니다
메서드의 인자로 전달되는 'public'은 연결할 디렉토리의 이름입니다
(javascript, css, img...)
정적 파일 연결이 끝나면 'public' 디렉토리 속에 있는 데이터들은
클라이언트(브라우저)의 요청에 따라 서비스를 제공해줄 수 있게 됩니다
views 디렉토리의 html 파일과 public 디렉토리의 js, css 파일을
연결하려면 링크를 아래와 같이 설정해야 합니다
경로의 개념을 확실히 짚고 갑시다
[html]
<link rel="stylesheet" href="/css/index.css">
<script src="/js/index.js"></script>
views > user 디렉토리에 html 파일을 새로 생성하겠습니다
[join.html]
<form action="/user/join" method="post">
<input type="text" name="userid" placeholder="아이디를 입력해주세요">
<input type="password" name="userpw" placeholder="패스워드를 입력해주세요">
<button type="submit">전송</button>
</form>
[server.js]
app.get('/user/join', (req,res)=> {
res.render('user/join.html')
// render 메서드는 해당 경로의 view 파일을 렌더링합니다
})
app.post('/user/join', (req,res)=>{
// join 페이지의 post 요청에 응답합니다
console.log(req.body)
})
아이디와 패스워드를 입력하고 전송버튼을 누르면 콘솔에 undefined가 출력되는데
이것은 아직 POST 리퀘스트의 바디 데이터를 제대로 읽어들이지 못하는 상태이기 때문입니다
- body-parser
요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어 입니다.
(최근 버전의 익스프레스는 body parser 기능을 기본적으로 제공하고 있지만
과거에는 관련 모듈을 따로 설치해야 했다고 하네요)
서버 자바스크립트 파일에 다음 코드(미들웨어)를 추가합니다
app.use(express.urlencoded({extended:false}))
// 이 미들웨어는 body-parser 역할을 합니다
// 옵션 {extended:false} 입력
만약 아무 옵션을 주지 않으면 다음 문구가 출력됩니다
body-parser deprecated undefined extended: provide extended option
+) 여기서는 false 옵션을 사용했지만 이 경우 객체속의 객체를
파싱하지 못하는 문제가 있다고 합니다
서버를 재가동후 전송버튼을 누르면 입력한 정보가 객체에 담겨서 출력됩니다
{
userid: 'web7722',
userpw: '1234',
}
이것으로 body parsing도 끝났습니다
nunjucks를 사용할 때 변수를 추가해서 간단한 수준의
동적 페이지를 구현하는 것이 가능합니다
res.render를 호출할 때 나타내고자 하는 변수를 {{}}
안에 담기만 하면 끝
[html]
<h1>{{name}}님 환영합니다</h1>
[server.js]
app.get("/", (req, res) => {
const name = req.query.name
res.render("index.html", {name})
}
);
이제 주소창 끝에 ?/name=
을 추가하고 그 값으로
아무 텍스트나 입력하면 입력한 변수가 페이지에 출력됩니다
끝으로 리디렉션 방법에 대해서도 알아보겠습니다
app.get('/user/join', (req,res)=> {
res.render('user/join.html')
})
app.post('/user/join', (req,res)=>{
res.redirect("/user/welcome")
// 전송버튼을 누를 때 해당경로로 리디렉션을 요청하는 라우트
})
app.get("/user/welcome", (req,res)=> {
res.send("환영합니다")
// 따로 제작한 페이지를 출력하려면 res.render 사용
})
post 요청에 대응할 때 응답 메서드인 redirect()
를 사용하면
지정한 경로로 강제이동합니다
(res.redirect
는 이동하고자 하는 url을 입력,
res.render
는 디렉토리의 파일을 읽는 메서드
각각은 POST, GET요청과 짝을 이룹니다)
이하 기록보관용 예제코드
const express = require("express");
const nunjucks = require("nunjucks")
const app = express(); // === const server = net.createServer()
const PORT = process.env.SERVER_PORT || 3000;
// 호스트 경로는 익스프레스가 자동으로 잡아줍니다
// nunjucks 기본 세팅
app.set('view engine','html')
nunjucks.configure('views', {
express:app
})
// // next 인자가 호출되지 않으면 아래의 get메서드는 실행되지 않습니다
// app.use((req, res, next)=> {
// console.log("ok")
// res.send("hello world2")
// next()
// })
// use메서드를 써서 정적 파일연결, public 디렉토리 내용을 로드합니다
// next함수는 자동실행됩니다
app.use(express.static("public"))
// http://127.0.0.1:3000/css/index.css
// http://127.0.0.1:3000/js/index.js
// css, js파일을 html에 출력하려면 템플릿 엔진이 필요합니다 (nunjucks)
app.use(express.urlencoded({extended:false}))
// body-parser 역할을 하는 미들웨어입니다
// // 이렇게 콜백을 밖에 꺼내는 것도 가능합니다
// const callback = (req,res,next) => {
// console.log('hello world3')
// next()
// }
// app.use(callback)
app.get("/", (req, res, next) => {
// http://localhost:3000/?name=ingoo
console.log(req.query.name);
// query.name이 없으면 undefined를 출력합니다
next();
// next 함수가 호출되면 아래의 콜백함수(미들웨어)를 실행
},
(req, res) => {
// res.send("hello world");
// 웹서버가 클라이언트에 응답할 때 보낼 메세지입니다
const name = req.query.name
res.render("index.html", {name})
// render 메서드 ~ public 디렉토리의 파일들을 읽어서 응답합니다
}
);
// http://127.0.0.1:3000/user/join
app.get('/user/join', (req,res)=> {
res.render('user/join.html')
})
app.post('/user/join', (req,res)=>{
// console.log(req.body)
const {userid,userpw,username} = req.body
console.log(userid,userpw,username)
// > undefined가 출력된다면 body parsing이 되지 않았기 때문
// res.send('hello') // 입력폼을 채우고 전송버튼을 눌렀을 때(post 요청시) 출력될 메세지
res.redirect("/user/welcome") // 전송버튼을 누를시 해당경로로 리디렉션을 요청
})
app.get("/user/welcome", (req,res)=> {
res.send("회원가입 성공")
// 리디렉션시 직접 만든 페이지를 출력하려면 res.render 사용
})
app.listen(PORT, () => {
console.log("server start");
});
// === server.listen