ํ์คํ ์น๐ ๊ฐ๋ฐ์ ์ง๋ง์ ๐ง๐ฝโ๐ป
โ ์ธ๊ณต์ง๋ฅ ๊ด์ฌ ๐ค
Categories
-
โฃ
โถ COMPUTER_SCIENCE
๐: 7 -
โฃ
โถ WEB
๐: 3 -
โฃ
โถ ETC
๐: 3-
โ
โฃ
ETCS
๐: 10 -
โ
โฃ
SUBBRAIN ๊ฐ๋ฐ๊ธฐ
๐: 5 -
โ
โ
YOS ๊ฐ๋ฐ๊ธฐ
๐: 1
-
โ
โฃ
-
โ
โถ AI
๐: 9-
โฃ
AITOOLS
๐: 3 -
โฃ
CV
๐: 2 -
โฃ
DEEP_LEARNING
๐: 1 -
โฃ
DATA_VIS
๐: 2 -
โฃ
GRAPH
๐: 1 -
โฃ
LIGHTWEIGHT
๐: 1 -
โฃ
MATH
๐: 1 -
โฃ
NLP
๐: 3 -
โ
STRUCTURED_DATA
๐: 2
-
โฃ
ExpressJs ํ์ต
Express.js
Fast, unopinionated, minimalist web framework for Node.js
Node.js ๊ธฐ๋ฐ์ ์ฌํํ ์น ํ๋ ์์ํฌ, ์ฃผ๋ก ๋ฒก์๋ ์๋ฒ๋ฅผ ๋ง๋๋๋ฐ ์ฌ์ฉํ๋ค.
์ ๋ง ๊ธฐ๋ณธ์ ์ธ ์๋ฒ์ด๊ณ , MIT ๋ผ์ด์ผ์ค ์ด๋ฏ๋ก, ์ข๊ฒ ๋งํ๋ฉด ๊ฐ๋ณ๊ณ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์ ์ฝ์์ด ๊ตฌํํ๊ธฐ ์ฌ์ฐ๋ฉฐ, ๋์๊ฒ ๋งํ๋ฉด ๋ง์ ๋ถ๋ถ์ ์ง์ ๊ตฌํํด์ผ ํ๋ค.
๋์ฑ ์์ธํ ์ฌํญ์ Express.js ๊ณต์ ๋ฌธ์ ์ฐธ์กฐ ๋ฐ๋.
๊ฐ๋ฐ ํ๊ฒฝ ๋ฐ ๊ธฐ๋ณธ ๊ตฌ๋ ์ค์ (Configure Dev settings.)
์ค์น(Install)
๊ธฐ๋ณธ์ ์ผ๋ก ์ต์ ๋ฒ์ ์ Node.js๊ฐ ์ค์น๊ฐ ๋๋ ์ํ์ฌ์ผ ํ๋ค.
$ mkdir myapp # ํ๋ก์ ํธ ํด๋ ์์ฑ
$ cd myapp # ํ๋ก์ ํธ ํด๋ ์ด๋
$ npm init # ๊ธฐ๋ณธ์ ์ธ ํ๋ก์ ํธ ์ค์ , package.json ์์ฑ
$ npm install express --save # node_modules์ express ์ค์น ๋ฐ dependency ์ค์
์ด ๊ธ์์๋ package.json
์์ฑ ์ค์ ์ ๊ธฐ๋ณธ๊ฐ์ ์ ์ ๋ก ํ๋ค. ์ถ๊ฐ์ ์ธ ์ค์ ์ ๋ฐ๋ผ ์ผ๋ถ ์ฉ์ด๊ฐ ๋ฐ๋ ์ ์๋ค. ์๋ฅผ ๋ค๋ฉด,
main
ํญ๋ชฉ์index.js
๋์app.js
๋ก ์ฌ์ฉํ ๊ฒฝ์ฐ,app.js
๋ก ์์ฑํด์ผ ํ๋ค.- Javascript ๋์ Typescript๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค.
- ์์ธํ ์ฌํญ์ Node.js ์ฐธ์กฐ
๊ธฐ๋ณธ ์ธํ (Default setting)
์ดํ, index.js
ํ์ผ์ ํ์ฑํ์ฌ ์๋์ ๊ฐ์ด
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
์ดํ node index.js
๋ฅผ ์ฝ์์ ์
๋ ฅํ๋ฉด ์๋์ ๊ฐ์ ๋ฉ์์ง๊ฐ ํ์๋๋ค.
$ node index.js
Example app listening at http://localhost:3000
http://localhost:3000
์ฃผ์๋ฅผ ์
๋ ฅํ์ฌ ๋ค์ด๊ฐ๋ณด๋ฉด ์๋์ ๊ฐ์ ์ฐฝ์ด ํ๊ธฐ๋๋ค.
์ถ๊ฐ์ ์ผ๋ก Nodemon์ด๋ Typescript ์ค์ ์ ํด์ฃผ๋ ๊ฒ๋ ๋์์ง ์๋ค.
๊ธฐ๋ฅ
๋ผ์ฐํ (routing) ์ค์
๋ผ์ฐํ ๊ธฐ๋ณธ(Basic Routing)
Express.js๋ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ก ๋ผ์ฐํ ํ๋ค.
app.METHOD(PATH, HANDLER)
-
app
์ express์ ์ธ์คํด์ค์ด๋ค. -
METHOD
๋ get, post ๋ฑ์ ์ํ๋ HTTP ์์ฒญ ๋ฉ์๋์ด๋ค. -
PATH
๋ ๋ผ์ฐํ ํ ๊ฒฝ๋ก์ด๋ค. -
HANDLER
๋ ํด๋น ์ฃผ์๋ก ๋ผ์ฐํ ๋ฌ์ ๋ ์คํ๋๋ ํจ์์ด๋ค.
์ด๋ฌํ ๋ผ์ฐํ
์ค์ ์ app.listen(path, [callback])
ํจ์๊ฐ ์คํ๋๊ธฐ ์ ์ ๋๋ง์น๋ฉด ๋๋ค.
app.post('/', function (req, res) {
res.send('Got a POST request')
}) // post ์์ฒญ
app.listen(port, () => { // backend ์คํ
console.log(`Example app listening at http://localhost:${port}`)
})
๋ผ์ฐํ ์ธ์ (Route parameters)
๋ค์๊ณผ ๊ฐ์ด :
๋ฅผ ์ด์ฉํด url ์ธ์๋ฅผ ์ป์ด๋ผ ์ ์๋ค.
app.get('/users/:userId/books/:bookId', function (req, res) { // ex) http://localhst:3000//users/42/books/21
res.send(req.params) //":userId"(="42") ๋ถ๋ถ๊ณผ ":bookId"(="21") ๋ถ๋ถ์ ์กด์ฌํ๋ ๊ฐ๋ค์ด string ํ์
์ผ๋ก ํ์.
})
์ด๋ ์ธ์์ ์ด๋ฆ์ผ๋ก ์ซ์์ ์์ด ๋์๋ฌธ์๋ง ๊ฐ๋ฅํ๋ค.
์ฆ, ํน์๋ฌธ์๊ฐ ๋ค์ด๊ฐ๋ฉด ํน์๋ฌธ์ ์ด์ ๊น์ง๋ง ์ธ์์ ์ด๋ฆ์ผ๋ก ์ธ์ ๋๋ค.
app.get('/flights/:to-:from', function (req, res) { // ex) http://localhst:3000/flights/LAX-SFO
res.send(req.params) //":to-:from" ์ ์ฒด๋ฅผ ๋ณ์๋ช
์ผ๋ก ์ธ์ํ๋ ๊ฒ์ด ์๋ :to"(="LAX") ๋ถ๋ถ๊ณผ ":from"(="SFO") ๋ถ๋ถ์ ์กด์ฌํ๋ ๊ฐ๋ค์ด string ํ์
์ผ๋ก ํ์.
})
๋ผ์ฐํ Extras (Routing extras)
๋ผ์ฐํ ์ ๊ท ํํ์(Routing Regular Expression)
๋ผ์ฐํ ์ ์ ๊ท ํํ์ ์ด๋ ๋ฌธ์์ด ํจํด์ ์ด์ฉํ ์ ์๋ค.
๋ฌธ์์ด ?
,+
,*
, ()
,$
์ ๋ฌธ์์ด ํจํด์ผ๋ก ์ด์ฉ๋๋ฉฐ, ํนํ $
์ ์ด์ฉํ๊ณ ์ถ์ผ๋ฉด [\$]
๋ก ๋์ ์
๋ ฅํด์ผํ๋ค.
?
์ ๋ฐ๋ก ์ ๋ฌธ์ ํ๋๋ฅผ optionalํ๊ฒ ๋ง๋ ๋ค.
app.get('/ab?cd', function (req, res) {// acd, abcd๋ก ์ฐ๊ฒฐ
res.send('ab?cd')
})
+
๋ ๋ฐ๋ก ์ ๋ฌธ์ ํ๋๋ฅผ ๋ฐ๋ณต ๊ฐ๋ฅํ๊ฒ ๋ง๋ ๋ค.
app.get('/ab+cd', function (req, res) {// abcd, abbcd, abb..bcd ๋ก ์ฐ๊ฒฐ
res.send('ab+cd')
})
*
์ ๋ชจ๋ ๊ธธ์ด์ ๋ชจ๋ ๋ฌธ์์ด์ด ๋ค์ด๊ฐ ์ ์์์ ์๋ฏธํ๋ค.
app.get('/ab*cd', function (req, res) {// ab์ cd ์ฌ์ด์ ๋ฌด์จ ๋ฌธ์๊ฐ ๋ค์ด๊ฐ๋ ์ฐ๊ฒฐ(ex) ab/์ด๊ฒ๋์ฐ๊ฒฐ๊ฐ๋ฅ/cd)
res.send('ab*cd')
})
()
์ ์์ ๋ฌธ์์ด ํจํด๋ค๊ณผ ํจ๊ป ์ฌ์ฉ๋๋ฉฐ, ๋์์ ๋ฌธ์ ํ๋ ๋์ , ()
์ฌ์ด์ ์กด์ฌํ๋ ๋ฌธ์์ด์ ๋์์ผ๋ก ํ๋ค.
app.get('/ab(cd)?e', function (req, res) {//abcde, abe๋ก ์ฐ๊ฒฐ
res.send('ab(cd)?e')
})
ํ๋ฒํ ์ ๊ท ํํ์ ๋ํ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
app.get(/.*fly$/, function (req, res) {//fly๋ก ๋๋๋ ์ฃผ์๋ก ์ฐ๊ฒฐ
res.send('/.*fly$/')
})
route ํจ์(route function)
๋ง์ฝ์ ๋์ผํ ์ฃผ์๋ก ์ฌ๋ฌ ๋ฉ์๋์ ๋ฐ๋ผ ๋์์ ๋ฌ๋ฆฌํ๋ฉด์, ํจ์ ์ฒด์ด๋์ ํตํด ์ฝ๋์ ์ค๋ณต์ ์ค์ด๊ณ ์ถ๋ค๋ฉด, route(path)
ํจ์๋ all(path, callback, [,callback ...])
์ ์ด์ฉํ๋ฉด ๋๋ค.
app.route('/book')
.get(function (req, res) { // get ์์ฒญ ์์ ๋์
res.send('Get a random book')
})
.post(function (req, res) { // post ์์ฒญ ์์ ๋์
res.send('Add a book')
})
.put(function (req, res) { // put ์์ฒญ ์์ ๋์
res.send('Update the book')
})
app.all('/user', function(req, res, next){
res.send('Accessing the user section')
next()
})
Router ํด๋์ค(Router Class)
express.Router
ํด๋์ค๋ ๋ผ์ฐํ
์ ํ์ฉํ ์ ์๋ ๋ฏธ๋ค์จ์ด์ด๋ค. ์ถ๊ฐ์ ์ธ ๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ์ ์ฉํ์ฌ ์ฌ์ฉํ๊ฑฐ๋, ๋ผ์ฐํฐ๋ฅผ ๋ชจ๋ํ, ํ์ผ ๊ตฌ์กฐ ๋ผ์ฐํ
๋ฑ์ ํ๋๋ฐ ์ฌ์ฉํ๋ค.
๐ต ํ์ผ ๊ตฌ์กฐ ๋ผ์ฐํ (File-system Routing) : Next.js์ ๊ธฐ๋ฅ์ฒ๋ผ ํด๋์ ํ์ผ๊ฒฝ๋ก๋ฅผ url ์ฃผ์๋ก ์ด์ฉํ์ฌ ๋ผ์ฐํ ํ๋ ๋ฐฉ๋ฒ.
var express = require('express')
var router = express.Router()
// ๋ผ์ฐํฐ๊ฐ ์ฌ์ฉํ ๋ฏธ๋ค์จ์ด ํจ์ ์ ์, ํ์ฌ ์ด ๋ผ์ฐํฐ ์ธ์คํด์ค๋ก ์ ๋ฌ๋๋ ์์ฒญ๋ง๋ค ์คํ๋จ
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now()) // ํ์ฌ ์๊ฐ ์ถ๋ ฅ
next() //next ํจ์ : ๋ค์ ๋ฏธ๋ค์จ์ด ๊ธฐ๋ฅ(=์ฌ๊ธฐ์ ๋ผ์ฐํ
)์ ๋ถ๋ฌ์ฎ.
})
// ํํ์ด์ง ๊ฒฝ๋ก ์ค์
router.get('/', function (req, res) {
res.send('Birds home page')
})
// /about ๊ฒฝ๋ก ์ค์
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
์ดํ, ํด๋น ๋ผ์ฐํ ํด๋์ค๋ฅผ ๋ฏธ๋ค์จ์ด๋ก ๋ถ๋ฅธ ๋ค, ๊ฒฝ๋ก๋ฅผ ์ค์ ํด์ฃผ๋ฉด, ํจ์๊ฐ ์ ์ฉ๋ ํ์ผ ๊ตฌ์กฐ ๋ผ์ฐํ ์ด ๊ฐ๋ฅํ๋ค.
var birds = require('./birds')
app.use('/birds', birds)
// "birds/" ๊ฒฝ๋ก์ "birds/about/"๊ฒฝ๋ก๊ฐ ์ด์ฉ ๊ฐ๋ฅํด์ง.
router.all(path, callback, [,callback ...])
ํจ์์ ์ฝ๋ฐฑ ํจ์๋ค์ ์ด์ฉํ๋ฉด ์ ์ญ ์ธ์ฆ ๋ฑ์ ๊ตฌํ ๊ฐ๋ฅํ๋ค, ๋ชจ๋ํ๊ฐ ๊ฐ๋ฅํ๋ค๋ ์ ์ ์ ์ธํ๊ณค, app.all(path, callback, [,callback ...])
๊ณผ ๋ค๋ฅธ์ ์์ด๋ณด์ธ๋ค.
router.all('*', requireAuthentication, loadUser) // '*'๋ฅผ ์ด์ฉํ ๋ผ์ฐํฐ๋ฅผ ๋ชจ๋ ๋ผ์ฐํฐ๋ณด๋ค ๋จผ์ ์ ์ํ๋ฉด ๋ชจ๋ url์ ์ ์ฉ๋๊ฒ ํ ์ ์๋ค.
// requireAuthentication : ์ธ์ฆ์ ๊ด๋ จ๋ ํจ์
// loadUser : ์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
router.all(path, callback, [,callback ...])
์ ํฌํจํด router.METHOD(path, [callback, ...] callback)
ํจ์๋ค์ ์ฒซ๋ฒ์งธ ์ธ์๋ก url, ๋๋ฒ์งธ๋ถํฐ๋ ์ฐจ๋ก๋๋ก next()
๋ฅผ ๋ถ๋ฅผ ๋๋ง๋ค ์คํ๋๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค.
// ์์ ์์ ์ฝ๋์ ๋์ผํ ๋์์ ํ๋ ์ฝ๋
router.all('*', requireAuthentication)
router.all('*', loadUser)
์๋ต ๋ฐฉ๋ฒ(Response methods)
ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ ๋ณด๋ผ ๋ ์ฌ์ฉํ ์ ์๋ ํจ์, ์ด ํจ์๋ฅผ ๋ถ๋ฆ์ผ๋ก์จ, ํด๋ผ์ด์ธํธ๋ ๋๊ธฐ ์ํ๋ฅผ ๋๋ด๊ณ ์์ฒญ-์๋ต ์ฌ์ดํด์ด ์ข ๋ฃ๋๋ค.
res.send([body])
: HTTP ์๋ต์ ๋ณด๋. ์ฃผ๋ก ๋น์คํธ๋ฆผ ์๋ต์ ์ฌ์ฉ๋จ
app.get('/', (req, res) => {
res.send('Hello World!') // Hello World! ๋ผ๋ ์๋ต์ ๋๋๋ฆผ
})
app.get('/json', (req, res) => {
res.send({messange: "ok"})// Json ํ์์ผ๋ก ์๋ต์ ๋๋๋ฆผ
})
app.get('/octet', (req, res)=>{
res.set('Content-Type', 'text/html')// Content-Type์ text ํํ๋ก ๊ฐ์
res.status(500).send('unavailable') // 500 ์ฝ๋์ ํจ๊ป ์๋ต
})
๋ง์ฝ, ์๋ต์ด JSON
ํ์์ ๋ง์ง ์์ ๊ตณ์ด res.set(field[, value])
ํ์์ ๋ฐ๊ฟ์ค์ผ ํ๋ค๋ฉด, ์ฐจ๋ผ๋ฆฌ res.json()
๋ฅผ ์ด์ฉํ์ฌ ์ฝ๋์ ๊ธธ์ด๋ฅผ ์ค์ด์.
app.get('/', (req, res) => {
res.json('Hello World!') // string์์๋ Content-Type์ application/json;
})
res.append(field[, value])
: HTTP ์๋ต ํค๋์ ํ๋์ ๊ฐ์ ์ถ๊ฐ,res.set(field[, value])==res.header(field[, value])
์ ์ด์ฉํ๋ฉดobeject
๋ฅผ ์ฃผ์ด ์ฌ๋ฌ ๊ฐ์ ๋์์ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ๋ค.
res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>'])
res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly')
res.attachment([filename])
์ ํตํ์ฌ Content-Disposition
ํค๋๋ฅผ ์ค์ ํด์ค ์ ์๋ค.
res.attachment('path/to/logo.png')
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png
์ข ๋ ์ฟ ํค๋ฅผ ์ธ๋ถํํ์ฌ ์ ํด์ฃผ๋ ค๋ฉด res.cookie(name, value [, options])
ํจ์๋ฅผ ์ฌ์ฉํ ์ ์๊ณ , res.clearCookie(name, value [, options])
ํจ์๋ก ์ง์์ค ์ ์๋ค.
res
.status(201)
.cookie('access_token', 'Bearer ' + token, {
expires: new Date(Date.now() + 8 * 3600000) // cookie will be removed after 8 hours
})
.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })
.redirect(301, '/admin')
res.redirect([status,] path)
: ๋ค๋ฅธ URL๋ก ๋ฆฌ๋ค์ด๋ ํธ ํด์ค๋ค. ๊ธฐ๋ณธ status ์ฝ๋๋302 Found
์ด๋ค.
res.redirect(301, 'http://example.com')
res.redirect('../login')
res.redirect('back')//์ด์ referer๋ก ๋๋ฆผ
res.render(view [, locals] [, callback])
: HTML view๋ฅผ ๋ณด๋ธ๋ค.view
: html ํ์ผ์ด ์กด์ฌํ๋ ํ์ผ ๊ฒฝ๋กlocals
: view์์ ์ด์ฉํ ๋ก์ปฌ ๋ณ์๋ค์object
ํํcallback
: ์๋ฌ์ html ํ์ผ์ ๋ฌธ์์ด์ ์ธ์๋ก ๊ฐ์ง๊ณ ์๋ ์ฝ๋ฐฑ ํจ์
// view์๊ฒ ๋ก์ปฌ ๋ณ์ ์ ๋ฌํ๊ธฐ
res.render('html/user', { name: 'Tobi' }, function (err, html) {
if (err) {
res.status(400).send('error!')
} else {
res.send(html)
}
})
res.download(path [, filename] [, options] [, fn])
:path
์ ์กด์ฌํ๋ ํ์ผ์attachment
๋ก ๋ณด๋ด๋ฉฐ, ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค์ด๋ก๋๋ฅผ ์งํํ๋ค.filename
์ธ์๋ ๋ค์ด๋ก๋ ๋ ํ์ผ ๋ช ์ผ๋ก, ์ฃผ์ด์ง์ง ์์๋ค๋ฉด,Content-Disposition
ํ๋์filename=
์ธ์๊ฐ ๊ธฐ๋ณธ๊ฐ์ด๋ค.
res.download('/report-12345.pdf', 'report.pdf', function (err) {
if (err) {
// ์๋ฌ ํธ๋ค๋ง
} else {
}
})
์ด์ธ์ ์ถ๊ฐ์ ์ธ ๋ฉ์๋๋ค์ ์ฌ๊ธฐ ์ฐธ์กฐ
์ ์ ํ์ผ(static file) ์ค์
Express.js
๋
serve-static
๋ชจ๋์ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ ๋นํธ์ธ ๋ฏธ๋ค์จ์ด(built-in middleware) ํจ์์ธ express.static
์ด ์กด์ฌํ๋ค.
์ด๋ฅผ ์ด์ฉํด ์ด๋ฏธ์ง, CSS ํ์ผ, JS ํ์ผ ๋ฑ์ ์ ์ ํ์ผ์ ์ด์ฉํ ์ ์๋ค.
express.static(root, [options])
-
root
์ธ์๋ ์ ์ ์์ ๋ค์ด ์์นํ ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๋ค. -
[options]
์ธ์๋static
ํจ์๊ฐ ๊ฐ์ง ์ ์๋ ์ต์ ์ด๋ค. ์๋ฅผ ๋ค๋ฉดdotfiles
:.
์ผ๋ก ์์ํ๋ ํ์ผ๊ณผ ํด๋๋ ์ด๋ป๊ฒ ๋ค๋ฃฐ ๊ฒ์ธ๊ฐ? ex)"ignore"
: ์๋ ๊ฑธ๋ก ์ทจ๊ธ. (default :"allow"
, ํน๋ณํ ์กฐ์น ์ทจํ์ง ์์)etag
: HTTP ์๋ต ํค๋์ETag
ํค๋๋ฅผ ์ถ๊ฐํ๋ค. (default:"true"
, weak ETag)lastModified
: HTTP ์๋ต ํค๋์Last-Modified
ํค๋๋ฅผ ์ถ๊ฐํ๋ค. (default:"true"
)
๋ฑ์ด ์กด์ฌํ๋ค.
app.use(express.static('public'))
์์ ๊ฐ์ ์ฝ๋์ผ ๊ฒฝ์ฐ, ์๋์ ๊ฐ์ ๊ฒฝ๋ก์ public
ํด๋์ ํ์ผ๋ค์ url์ ํตํด ์ ๊ทผ ํ ์ ์๋ค.
|-public/
| |-hello.html
| |-css/
| | |-main.css
| |-images/
| | |-dog.png
| |-js/
| | |-SPA.js
http://localhost:3000/hello.html
http://localhost:3000/css/main.css
http://localhost:3000/images/dog.jpg
http://localhost:3000/js/SPA.js
์ถ๊ฐ๋ก, ๊ฒฝ๋ก ์ ๋์ด๋ฅผ ์ด์ฉํ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์ด์ฉํ๋ฉด ๋๋ค.
app.use('/static', express.static('public'))
http://localhost:3000/static/hello.html
http://localhost:3000/static/css/main.css
http://localhost:3000/static/images/dog.jpg
http://localhost:3000/static/js/SPA.js
DB ์ฐ๊ฒฐ(DB Connection)
DB ์ฐ๊ฒฐ ๋ฐฉ๋ฒ์ ๊ณต์ ๋ฌธ์ ์ DB ๋ณ๋ก ์์ธํ ์ค๋ช ๋์ด ์๋ค.
๊ฐ๊ธฐ DB์์ ์ง์ํ๋ ๋ชจ๋์ ์ด์ฉํ๋ ๋ฐฉ์์ผ๋ก ์งํ๋๋ฉฐ, ์ฌ๊ธฐ์๋ MySQL๊ณผ MongoDB์ ์์๋ฅผ ์์๋ณด๊ฒ ๋ค.
MySQL
npm install mysql
mysql์์ ์ง์ํ๋ npm ๋ชจ๋์ ์ค์นํ๋ค. mysqljs github ์์ ์ข๋ ์์ธํ ์ฌํญ์ ์ ์ ์๋ค.
var mysql = require('mysql')
var connection = mysql.createConnection({
// ์ค์ ๋ก๋ env ์ค์ ํ ๊ฒ!
host: 'localhost',
port: '3306',
user: 'dbuser',
password: 's3kreee7',
database: 'my_db',
debug: ENV.PRODUCTION, // true ์, ์ฝ์ ์ฐฝ์ SQL ์ฟผ๋ฆฌ ์งํ์ด ์ถ๋ ฅ๋จ
supportBigNumbers: true, // db์ BIGINT๋ DECIMAL ํ์
์ ๋ฐ์ดํฐ ํฌ๊ธฐ์ ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ง์ํ์ง ์์ผ๋ฏ๋ก, ๋ฌธ์์ด ํ์์ผ๋ก ๋ฐ๊ฟ์ฃผ๋ ์ต์
ssl: {
// ssl ์ฐ๊ฒฐ ์ค์ ์ ์ํ ์ต์
}
})
connection.connect() // ์ฐ๊ฒฐ ์์
connection.query('SELECT 1 + 1 AS solution', function (err, rows, fields) { // SQL Mapping, ์ค์ ๋ก๋ ORM์ผ๋ก ์งํํ๋ ๊ฒ์ ์ถ์ฒ
if (err) throw err
console.log('The solution is: ', rows[0].solution)
})
connection.end() // ์ฐ๊ฒฐ ์ข
๋ฃ
MongoDB
npm install mongodb
๋ง์ฐฌ๊ฐ์ง๋ก, MongoDB NodeJS๋ฅผ ์ํ ๋๋ผ์ด๋ฒ๋ฅผ ์ด์ฉํ๋ฉด ๋๋ค.
var MongoClient = require('mongodb').MongoClient
MongoClient.connect('mongodb://localhost:27017/animals', function (err, client) {
if (err) throw err
var db = client.db('animals')
db.collection('mammals').find().toArray(function (err, result) {
if (err) throw err
console.log(result)
})
})
Node.js์ MongoDB๋ฅผ ํจ๊ป ์ธ๋๋, Mongoose์ ํจ๊ป ์ฐ๋ ๊ฒ๋ ๊ณ ๋ คํด๋ณผ๋ง ํ๋ค.
Mongoose๋ฅผ ์ด์ฉํ๋ฉด ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฌ๋ฆฌ ์์ ๋ก์ด ํ์์ ๊ฐ์ง๋ ์ฝ๋ ์ (Collection)๋ค์ ํ์์ ์ ์ํ๊ณ , ์ ์ฝ(Constraint)์ ์ค์ ํด์ค ์ ์๋ค.
npm install mongoose validator
Mongoose๊ฐ ๋์ MongoDB์ ์ฐ๊ฒฐ์ ํ๋ฏ๋ก, MongoDB ์ฐ๊ฒฐ์ ํ์์๋ค.
let mongoose = require('mongoose');
const server = '127.0.0.1:27017'; // DB ์๋ฒ ์ฃผ์
const database = 'fcc-Mail'; // DB ๋ช
class Database {
constructor() {
this._connect()
}
_connect() {
mongoose.connect(`mongodb://${server}/${database}`)
.then(() => {
console.log('Database connection successful')
})
.catch(err => {
console.error('Database connection error')
})
}
}
module.exports = new Database()
ํ๋ก์ ์ค์ (Proxy setting)
Express.js์์๋ ๋ฆฌ๋ฒ์ค ํ๋ก์(Reverse Proxy)๋ฅผ ์ด์ฉํ ๊ฒฝ์ฐ,
proxy-addr
ํจํค์ง ๊ธฐ๋ฐ์ธ trust proxy
์ค์ ์ ํด์ฃผ์ด์ผ ์ ์ ์๋ํ๋ค.
์ด๋ฅผ ์ค์ ํด์ฃผ์ง ์๋๋ค๋ฉด, ํด๋ผ์ด์ธํธ์ IP ์ฃผ์ ๋์ , ๋ฆฌ๋ฒ์ค ํ๋ก์์ IP ์ฃผ์๋ฅผ ํด๋ผ์ด์ธํธ๋ก ์ฐฉ๊ฐํ๋ค๋ ๋ฏํ๋ค.
X-Forwarded-For: <client>, <proxy1>, <proxy2>
X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178
//X-Forwarded-For ํค๋์ ์์
์ด๋, HTTP ํค๋ ์ค X-Forwarded-for
ํค๋๋ฅผ ์ด์ฉํด ํด๋ผ์ด์ธํธ ์ฃผ์๋ฅผ ํ๋ช
ํ๋ฉฐ, ๋ณดํต ์ต์ข์ธก์ด ํด๋ผ์ด์ธํธ IP ์ฃผ์์ด๋ค.
app.set('trust proxy', true)
true
: HTTP ๋ฉ์์ง์ X-Forwarded-For
ํค๋์ ์ต์ข์ธก์ IP ์ฃผ์๋ฅผ ํด๋ผ์ด์ธํธ IP ์ฃผ์๋ก ์ค์
๐ต HTTP ๋ฉ์์ง์ X-Forwarded-For
, X-Forwarded-Host
, X-Forwarded-Proto
ํค๋๋ฅผ ๋ฆฌ๋ฒ์ค ํ๋ก์๊ฐ ๋ฎ์ด์ฐ๊ฒ ์ค์ ํ์ง ์์ผ๋ฉด, ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฅผ ์ด์ฉํด ๋ค๋ฅธ ํด๋ผ์ด์ธํธ์ธ ์ฒ ํ์ธํ ์ ์๋ค.
false
: ๋ฆฌ๋ฒ์ค ํ๋ก์๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉฐ, req.socket.remoteAddress
์ ์กด์ฌํ๋ IP ์ฃผ์๋ฅผ ํด๋ผ์ด์ธํธ๋ก ๊ฐ์ฃผ, ๊ธฐ๋ณธ๊ฐ
app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal', '123.123.123.123'])
๋ฆฌ๋ฒ์ค ํ๋ก์์ IP ์ฃผ์๋ฅผ ๋ช ์ํด์ค ์๋ ์๋ค. ์๋๋ ๋ฏธ๋ฆฌ ์ ์๋ ์๋ธ๋ท ๋ฌธ์์ด ๋ค์ด๋ค.
loopback
-127.0.0.1/8
,::1/128
linklocal
-169.254.0.0/16
,fe80::/10
uniquelocal
-10.0.0.0/8
,172.16.0.0/12
,192.168.0.0/16
,fc00::/7
์ด๋ ๋ช
์๋ IP ์ฃผ์๋ ์๋ธ๋ท์ ํด๋ผ์ด์ธํธ IP ์ฃผ์๊ฐ ์๋ ๊ฒ์ผ๋ก ํ๋จํ๋ฉฐ, req.socket.remoteAddress
์ ์ฃผ์๊ฐ ๋ช
์๋์ด ์๋ค๋ฉด(trusted), ํด๋น ๋ฉ์์ง์ X-Forwarded-For
ํค๋์ ๋ช
์ ๋ ์ฃผ์์์ ์ต์ฐ์ธก๋ถํฐ ์ข์ธก ์์ผ๋ก ํ์ธํ๋ฉด์ ๊ฐ์ฅ ์ฒซ๋ฒ์งธ๋ก ๋ช
์๋์ด ์์ง ์์(untrusted) ์ฃผ์๋ฅผ ํด๋ผ์ด์ธํธ ์ฃผ์๋ก ๊ฒฐ์ ํ๋ค.
app.set('trust proxy', 2)
์ซ์๋ฅผ ๋ช ์ํด์ค ๊ฒฝ์ฐ, ๋ช ํ์ ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ดํ์ ํด๋ผ์ด์ธํธ ์ฃผ์๊ฐ ๋์ค๋์ง๋ก ๊ฒฐ์ ํ๋ค๋ ์๋ฏธ์ด๋ค.
์๋ฅผ ๋ค์ด, 0
์ ๋ช
์ํ๋ฉด, ๋ฆฌ๋ฒ์ค ํ๋ก์๊ฐ ์กด์ฌํ์ง์์ผ๋ฉฐ, req.socket,remoteAddress
๊ฐ ํด๋ผ์ด์ธํธ ์ฃผ์๋ก ํ๋ช
๋๋ฉฐ, 1
์ ๋ช
์ํ๋ฉด, X-Forwarded-For
ํค๋์ ์ต์ฐ์ธก์์ ๋๋ฒ์งธ๋ฅผ ํด๋ผ์ด์ธํธ IP ์ฃผ์๋ก, ๋๋จธ์ง๋ง ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ฃผ์๋ก ๊ฒฐ์ ํ๋ค.
app.set('trust proxy', function (ip) {
if (ip === '127.0.0.1' || ip === '123.123.123.123') return true // trusted IPs
else return false
})
๋๋, ํจ์๋ฅผ ์ ์ํด์ฃผ์ด, ๋ฆฌ๋ฒ์ค ํ๋ก์๋ฅผ ํ๋ช
ํ ์ ์๋ค. true
์ผ ๊ฒฝ์ฐ ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ฃผ์์ด๋ฉฐ, X-Forwarded-For
ํค๋์ ๋ค์ ์ฃผ์๋ฅผ ํจ์์ ๋ฃ์ด๋ณด๊ฒ ๋๊ณ , false
์ผ ๊ฒฝ์ฐ ํด๋น IP ์ฃผ์๊ฐ ํด๋ผ์ด์ธํธ์ ์ฃผ์์ด๋ค.
trust proxy
์ค์ ์ดํ, req.hostname
์ ๊ฐ์ X-Forwarded-Host
ํค๋์์ ๊ฐ์ ธ์ค๊ฒ ๋๋ฉฐ, X-Forwarded-Proto
ํค๋๊ฐ ๋ฆฌ๋ฒ์ค ํ๋ก์์ ์ํด ๋ณ๊ฒฝ๋์ด ํ๋กํ ์ฝ ๋ฑ์ ํ์ธํ ์ ์๊ฒ ๋๋ฉฐ, req.ip
, req.ips
๊ฐ์ด ์ค์ ๋๊ฒ ๋๋ค.
๋ฏธ๋ค์จ์ด(Middleware)
๋ฏธ๋ค์จ์ด ํจ์๋?(About middleware function)
๋ฏธ๋ค์จ์ด ํจ์๋ ์์ฉํ๋ก๊ทธ๋จ์ ์์ฒญ-์๋ต ์ฌ์ดํด์ ์์ฒญ ๊ฐ์ฒด(request object)์ ์๋ต ๊ฐ์ฒด(response object), ๊ทธ๋ฆฌ๊ณ next()
ํจ์๋ฅผ ์ด์ฉํ๋ ํจ์์ด๋ค.
- ์์ฒญ ๊ฐ์ฒด(request object) : ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ HTTP ์์ฒญ์ ์์(์ฟผ๋ฆฌ ๋ฌธ์์ด, ์ธ์, ๋ฐ๋, ํค๋ ๋ฑ)๋ฅผ ํฌํจํ๊ณ ์๋ ๊ฐ์ฒด
- ์๋ต ๊ฐ์ฒด(response object) : ํด๋ผ์ด์ธํธ์๊ฒ ๋๋ ค์ค HTTP ์๋ต์ ์ํ ๊ฐ์ฒด, ํจ์๋ฅผ ํตํด ์๋ต ๋ฉ์์ง๋ฅผ ์กฐ์ฑํ๊ณ ์๋ตํ ์ ์๋ค.
next()
ํจ์ : ์คํ์ ๋ค์ ์์์ ๋ฏธ๋ค์จ์ด๋ฅผ ๋ถ๋ฌ์ค๋ ํจ์, ํด๋น ๋ฏธ๋ค์จ์ด์์ ํต์ ์ ์ข ๋ฃํ์ง ์๊ณ ๋ค์ ๋ฏธ๋ค์จ์ด๋ก ๋๊ธฐ๋ ค๋ฉด ์ด์ฉํด์ผ ํ๋ค.
๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ํตํด, ์ถ๊ฐ์ ์ธ ๋ก์ง์ ์คํํ๊ฑฐ๋, ์์ฒญ๊ณผ ์๋ต์ ๋ณํ์ ๊ฐํ๊ฑฐ๋, ํต์ ์ ์ข ๋ฃํ๊ฑฐ๋ ๋ค์ ๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ๋ถ๋ฌ์ฌ ์ ์๋ค.
์๋ฅผ ๋ค์ด, ์ธ์ฆ, ์ธ๊ฐ ์์คํ ์ ๊ตฌํํ๊ฑฐ๋, ํํฐ๋ง, ์บ์ฌ ๊ตฌํ ๋ฑ์ด ๊ฐ๋ฅํ๋ค.
var express = require('express')
var app = express()
var router1 = express.Router() // router-๋ ๋ฒจ ๋ฏธ๋ค์จ์ด ์์ฑ์ ์ํ ๋ผ์ฐํฐ ์ ์ธ
var router2 = express.Router()
app.use(function(req,res, next){ // ์์ฉํ๋ก๊ทธ๋จ ๋ ๋ฒจ ๋ฏธ๋ค์จ์ด ์์ฑ
console.log('middleware 1')
next()
})
router1.use(function (req, res, next) {
console.log('middleware 2')
next()
})
router1.use(function (req, res, next) {
console.log('middleware 3')
next()
})
router2.use(function (req, res, next) {
console.log('middleware 4')
next('router') // ํ์ฌ ๋ผ์ฐํฐ ๋ ๋ฒจ์ ๋ชจ๋ ๋ฏธ๋ค์จ์ด๋ฅผ skip
})
router2.use(function (req, res, next) {
console.log('middleware 5') // ์์ ๋ฏธ๋ค์จ์ด์์ ๋ผ์ฐํฐ ๋ ๋ฒจ ๋ฏธ๋ค์จ์ด๋ค์ skipํ๊ธฐ ๋๋ฌธ์ ์คํ๋์ง ์๋๋ค.
next()
})
app.use(function(req,res, next){
console.log('middleware 6')
next()
})
app.use('/', router1) // ๋ผ์ฐํฐ ๋ฏธ๋ค์จ์ด ์ ์ธ์ ๋นจ๋์ง๋ง, app์ ์ ์ฉ์ด ๋๋ฆฌ๋ฏ๋ก middleware 6๋ฒ๋ณด๋ค ๋ค์ ์คํ๋๋ค.
app.use('/', router2)
์ ์ฝ๋์ ์คํ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
middleware 1
middleware 6
middleware 2
middleware 3
middleware 4
์ ์ฉํ ๋ฏธ๋ค์จ์ด (Additional Middleware)
static
[[#์ ์ ํ์ผ(static file) ์ค์ | ์์]] ์ค๋ช ํ๋ Express.js ๋นํธ์ธ ๋ชจ๋, ์ ์ ํ์ผ์ ์ด์ฉํ๋๋ฐ ์ฌ์ฉํ๋ค. |
express.static(root, [options])
cors
npm install cors
CORS๋ Express ํ์์ ๋ง๋ ์๋ ํํฐ ๋ฏธ๋ค์จ์ด์ด๋ค.
CORS(Cross-Origin Resource Sharing, ๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ ) ์ค์ ์ ํตํด ์ ๊ทผ ๊ถํ์ ์ค์ ํ ์ ์๊ฒ ํ๋ค.
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: ['http://example.com', 'http://example2.com'], // '*'์ ์ด์ฉํ๋ฉด ๋ชจ๋ ์์ฒญ CORS ํ์ดํธ๋ฆฌ์คํธ.
optionsSuccessStatus: 200, // ์ค๋๋ ๋ธ๋ผ์ฐ์ ๋ ์ฝ๋ 204๋ฅผ ์ฐ๋ฏ๋ก 200์ผ๋ก ๊ฐ์
credentials: true
//'Access-Control-Allow-Credentials' CORS ํค๋ ์ค์ ์ฌ๋ถ
}
//์ผ๋ถ route์๋ง cors ์ ์ฉ ์์
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'})
})
// ๋ชจ๋ route์ cors ์ ์ฉ ์์
app.use(cors())
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
express-session
npm install express-session
Session ๋ฏธ๋ค์จ์ด๋ฅผ ํ์ฑํ ์ ์๊ฒ ํด์ฃผ๋ Express ํ์์ ๋ง๋ ์๋ ํํฐ ๋ฏธ๋ค์จ์ด.
Session์ ์ด์ฉํ์ฌ, ์ ์ ์ ์ฟ ํค๋ฅผ ์ ์ฅํ๊ณ , ์์ฒญ์ ์ ์ ๋ณ๋ก ๊ตฌ๋ถํ์ฌ, ๋ณด์๊ณผ ์ ์ ํนํ ์๋น์ค ๋ฑ์ ๊ตฌํํ ์ ์๋ค.
var app = express()
var sess = {
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: false }
}
if (app.get('env') === 'production') {
app.set('trust proxy', 1) // trust first proxy
sess.cookie.secure = true // serve secure cookies
}
app.use(session(sess))
helmet
npm install helmet
HTTP ํค๋ ์ค์ ์ ํตํด ์ดํ๋ ์ด์ผ์ด์ ๋ณด์ ํฅ์์ ๋์์ฃผ๋ ์๋ ํํฐ ๋ฏธ๋ค์จ์ด.
const express = require("express");
const helmet = require("helmet");
const app = express();
const helmet_setting = {
referrerPolicy: { policy: "no-referrer" }, // ์ธ๋ถ ๋ณด์ ์ค์
contentSecurityPolicy: false // ์ฌ์ฉ ์ํจ ์ค์
}
app.use(helmet(helmet_setting));
helmet ์ 15๊ฐ์ ๋ณด์ ๋ฏธ๋ค์จ์ด๋ฅผ ํฌํจํ๊ณ ์์ผ๋ฉฐ, ๊ฐ์ ์ค์ ๋ฐ ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ์กฐ์ ํ ์ ์๋ค.
_articles/web/backend/ExpressJs ํ์ต.md