- Node.js
= 정확히는 Node.js 런타임.
: 자바스크립트를 Node.js runtime이 해석해서, 서버의 기능들을 직접 컨트롤 할 수 있도록 도와준다.
- 한계
: 밑바닥부터 개발하면 번거롭다.
-> 웹에서 등장하는 반복 작업
- URL을 통해 전달된 데이터를 처리하는 것
- 정적 자바스크립트, 이미지 파일 = 에셋들을 사용자에게 제공하기 위해 일일히 구현
- 로그인 기능, 보안 기능
-> Node.js 기술로 매번 비슷한 작업을 구현하는 것은 비효율적이다.
- Node.js runtime이 제공하는 기술들은 상대적으로 로우레벨이다. 컨트롤하는 것을 Node.js이고, 구현을 위한 것이 Expres.js이다.
01. Express.js 프레임워크
= Node.js 위에서 동작하는 웹 프레임워크
[Javacript]
[Express.js] <- Node.js의 기능들을 활용해 미리 구현을 해놓은 기능들을 모아놓은 것.
[Node.js]
1) 프레임워크에 미리 구현된 기능 활용
- 요청 처리
- 동적 및 정적 컨텐츠 제공
- 데이터베이스 연결
=> 웹 프레임워크 사용의 장점: 애플리케이션 개발에 필요한 기능들이 대부분 집중.
2) 웹 사이트 개발자는 웹 사이트 개성에 집중할 수 있다.
요즘은 웹 프레임워크를 많이 사용해서 개발 속도를 올린다.
1. Express.js 패키지 설치
= 일종의 패키지.
- npm을 활용해서 express.js 설치
2. 첫 Express.js 애플리케이션의 작성
1) 애플리케이션에 express 모듈 추가
2) app에 express 웹 서버 애플리케이션 할당
: 내장 웹 서버 기능 포함
app에 express(); 할당
express 프레임워크는 기본적으로 내장 웹서버를 포함하고 있다.
원래는 http 모듈의 createServer 메소드를 사용해서 웹서버를 생성했다.
express는 기본적으로 내장 웹서버를 포함하기 때문에, 이렇게 호출하면 app이라는 변수에는 웹서버가 할당된다.
3) 홈페이지에 GET 라우트 세팅
: 별도의 다른 모듈 없이 GET 라우트 정의 방법 제공
라우트 방식과 유사하지만 다르다.
기존: route를 위해 등록함수들을 따로 만들었다. handle, get, post 임의로 제작해 콜백 함수가 등록되도록.
express는 기본적으로 내장되어 있기 때문에, GET 라우트 정의 방법을 제공한다.
get, post 등의 http 메소드들을 모두 제공한다.
별도로 만들 필요 없이 바로 라우팅을 정의 가능.
get이 들어왔을때 콜백함수 호출.
req, res 매개변수 - 안쪽에 있는 함수 내용을 처리.
4) 서버에서 클라이언트로의 응답 발행
res.send( ); 함수 활용.
앞에서는 없었다.
node.js에서는 writeHead - 헤더, write - 본문, end - 종료를 명시.
express.js에서는 send()만으로 end()까지 처리가 끝난다.
http 모듈에서 write()만 하고 end()를 빼먹을 경우, 요청 처리가 안된다.
클라이언트 입장에서 끝났다는걸 알지 못하기 때문에, 데이터를 계속 기다리게 된다.
=> 데이터 전송 완료를 보내야 한다.
5) 80번 포트로 요청 수신 대기 상태 설정
내장 웹서버이기 떄문에 바로 .listen(port, 어떤 내용을 실행할지의 콜백함수 등록 - 여기서는 간단하게 log)
=> 엄청나게 간단해졌다.
6) req 매개변수로의 접근
기본적으로 express.js에서 제공하는 매개변수들.
requset, respose에.
각각이 무슨 의미를 가지고 있는가?
- params: 나중에
- body: 요청하는 쪽에서 내용을 가지고 있을 때 들어가게 된다.
클라이언트 쪽에서 서버로 데이터를 보내는 경우: POST가 대표적. 이 경우, body 부분이 포함되어 있다.
GET도 body를 포함할수는 있다. 쿼리 스트링이 굉-장히 긴 경우. 단, 호환성이 떨어진다. 때문에 일반적으로 POST에만 존재한다고 생각하는게 맞다.
호스트 요청 처리시 활용된다.
- url: 방문된 URL에 대한 정보를 포함한다.
"/"는 요청을 할 때, IP주소 뒤에 아무것도 포함하지 않았기 때문에 붙는다.
- query: URL의 쿼리스트링으로부터 데이터 추출.
쿼리스트링은 ? 뒤쪽부터 꺼내온다.
7) Semantic URL
- 기존의 URL 방식: url을 통해, 클라이언트로부터 서버로 요청을 할 때, 요청하고자 하는 것에 대한 정보를 쿼리 스트링을 통해 말했다.
ex. ? id = HTML
- Semantic URL: 쿼리 스트링 대신 원하는 정보를 서버에게 요청할 수 있다. 이것 자체가 '의미가 있는 URL'로 번역된다.
ex. page/HTML
으로 '해석이 가능한'.
위가 기존의 URL.
아래가 Semantic URL.
=> express.js는 Semantic URL을 지원한다.
8) 경로 뒤에 "/:키"를 통해 키와 값을 전달
ex.
Route path: /users/:userID/books/:bookID == '/page/:pageId'
Request URL: http://localhost:3000/users/34/books/8989
=> 34, 8989라는 요청이 들어온 것
req.params: {"userId": "34", "bookId": "8989"}
이러한 객체 형식으로 표현.
키: 값의 형태.
다음처럼 접근이 가능하다.
다음과 같이 등록했다고 했을 때, URL에 HTML이 들어가있다면
params을 출력하면 다음과 같이 나온다.
request.params.pagdid에 접근하면 HTML이 나온다.
2. Express 웹 프레임워크
1) 는 미들웨어 함수들로 구성되어 있다.
- 미들웨어: 일반적으로 사용하는 용어.
애플리케이션 로직과의 데이터 교환 전에, 대기하고 분석하고 필터링하는 HTTP 통신을 다루는 코드.
웹, Node.js 플랫폼 사이에 존재하면서, 그 안에서 동작하는 일련의 함수들.
- 어떻게 동작하는가?
(1) 클라이언트가 HTTP 요청 전달
(2) 전달되는 뷰 페이지 = HTML 전달된다.
HTML이 만들어 지기까지, 데이터베이스에도 접근을 해야 한다.
클라이언트 요청이 들어와서 뷰 페이지 데이터베이스에 접근하기 전까지 처리하는 부분 = Express.js 미들웨어 함수이다.
-> URL 체크, 라우터 관리, 데이터 분석을 진행한다.
2) 대체 미들웨어 함수가 무엇인가?
- express application = 미들웨어 함수의 연속.
- 클라이언트 요청이 왔을 때, 그 요청에 대한 응답을 하는데, 그 과정에서 처리되는 함수.
- 세가지 매개변수를 가진다. req, res, next middleware 함수.
- 미들웨어 함수의 경우
1) 코드를 실행시키거나, 로직을 처리하거나
2) req/res 오브젝트 내용을 변경하거나
3) req/res cycle을 종료하거나 = 응답까지 끝낸다는 것.
-> 클라이언트에서 req가 들어오고, res가 되어야만 cycle이 끝난다.
이 사이에 있는 것이 미들웨어 함수.
4) 다음 미들웨어 함수를 호출하거나
3) 미들웨어 함수의 종류
(1) Application-level middleware
- app = express()를 통해서 app 객체를 만든다.
여기에 직접 연결되는 미들웨어들이 애플리케이션 레벨 미들웨어.
=> express를 통해서 생성된, 객체에 직접 연결되는 미들웨어.
- app.use(), get(), put(), post() = HTTP method.
- req, res에 접근해서 사용 가능, 변경 가능.
- next 함수를 이용해: 다음에 실행할 미들웨어 결정 가능.
+ next가 추가된다.
app.get()을 활용해, '/'에 get ㅇ청이 들어온다면 다음의 미들웨어 함수를 실행하겠다.
app.listen(3000) - 요청이 들어온다면 알아서 req에 내용이 채워져서 전달된다.
이것 또한 미들웨어 함수들이 변경해야 들어가게 된다.
next = 일종의 콜백.
현재 실행하고 있는 미들웨어 함수가 끝나면, 호출을 할 수도 있는 콜백 함수를 next로 등록하게 된다.
-> 어떻게 애플리케이션 레벨 미들웨어를 활용하는가?
1) use: 무조건 동작하는 함수.
- 첫번째 인수로 경로를 지정하면, 특정 경로에 대해서만 동작한다.
- 자동으로 밑의 내용이 호출된다.
2) GET, POST 등 전송 방식에 따라 동작하게 하려면 use 말고 get, post 사용.
3) 여러 미들웨어를 (하나의 라우터에) 이어서 정의 가능.
- app.use -> '/', 미들웨어 함수1, 미들웨어 함수2 . . .
여러개가 들어갈 수 있다.
- 여기서 next()를 호출하면 다음 미들웨어 함수 호출 -> 바로 다음의 함수 차례.
-> req.originalurl이 요청받으면
.com/이후의 뒤가 전부 다 출력된다.
결국 url과 동일하지만, url이 변경되더라도 오리지널은 여기에 남겨놓는다.
-> baseurl: 베이스가 되는 url. "/admin"을 베이스로 처리한다.
-> path: 쿼리 스트링이 시작되기 전까지가 들어간다.
req의 오브젝트에는 굉장히 다양한, 기본으로 제공되는 값들이 존재한다.
4) 한 경로에 GET에 대한 route가 여러개 등록된 경우
get = /user/id -> 먼저 ID값을 출력하고, 다음으로 user info를 보낸다.
여기서 중요한 것은 next를 호출하지 않았다는 것. send()를 하는 순간 사이클이 종료되기 때문이다.
밑에서는 똑같은 /user/:id에 대해서 -> send()하고 있다. 클라이언트 웹 페이지에 id가 보이게 될 것이다.
원래는 미들웨어 함수가 3개가 있어서 세개가 차례대로 실행될 것 같지만, 3번째는 실행되지 않는다. 2번째에서 next()가 호출되지 않기 때문이다.
여러개의 라우트가 등록된 경우, 다음 라우트로 어떻게 넘어갈까?
id값을 비교해서
1) 0이라면 - next('route')를 써주면 -> 다음 미들웨어 함수를 호출하지 않고, 현재 라우트를 건너뛴다. 때문에 두번째 get으로 향한다.
2) 0이 아니라면 - 다음 미들웨어를 실행한다.
다음과 같이 여러개의 라우트를 등록하고, 자유자재로 실행순서를 변경할 수 있다.
(2) Router-level middleware
app.use, app.get으로 사용하지 않고,
express.Router()로 객체를 생성해서 router로 할당한다.
애플리케이션 레벨 라우터와의 차이는
express()와 연결되느냐, express.Router()와 연결되느냐.
1) 애플리케이션 레벨 미들웨어와 유사하게 동작한다.
use의 경우: 첫번째 매개변수가 없다면, 모든 경우에 실행된다.
모든 요청에 대해서 실행되고자 할 때에는 첫번째 매개변수를 생략하고 미들웨어로 들어간다.
동일한 내용.
-> 그렇다면 왜 사용하는가?
코드를 분리하기 위해서.
애플리케이션의 규모가 커지면 라우터 등록만 해도 굉장히 길어지기 때문에, 하나의 소스코드에 몰아넣지 않고 경우에 따라 라우터 파일을 분리해야 한다.
때문에 라우터 레벨이 사용된다.
birds route.js 파일을 만든다 + module.exports = router
별도의 라우트 파일을 만들기 위한 자바스크립트 파일을 만들고 exports한다.
main.js에서 require('./birds')
app.use('birds', birds)
birds라는게 들어오면 './birds'로 전부 넣겠다는 의미.
ex. GET /birds/about 하면 -> birds route.js로 이동해서 about을 찾는다.
구조적으로 route를 만들 수 있다.
관리가 굉장히 쉬워진다.
=> 라우트를 분류해서 관리할 수 있게 된다.
(3) Error-handling middleware
다른 미들웨어와 같은 방식으로 동작하지만, 단 하나 큰 차이점이 있다.
반드시 매개변수가 4개여야 한다.
- err, req, res, next => { }
만약 에러가 발생한다면 에러 매개변수에 관련된 정보들이 담겨서 전달된다.
에러가 발생했을때 공통적으로 처리하는 코드를 넣어줄수도 있다.
next()에서 에러를 처리할수도 있다.
(3) Built-in middleware
기본적으로 제공되는 미들웨어.
-> express.static
정적인 에셋을 손쉽게 관리가 가능하다.
express.static으로 바로 호출이 가능하다.
public은 경로, 그곳에 /images, js, css 등이 존재할텐데, 그 디렉토리의 경로를 적어주면 정적 에셋을 담고있는 디렉토리라고 자동으로 인식한다.
옵션에는 여러가지 옵션을 설정할 수 있다.
하나하나 설명하지 않음.
다음의 링크에 옵션에 대한 설명이 있다.
public에 대해 설정하면, img 태그 등에 접근할때도 바로 /images/부터 접근할 수 있게 된다.
static도 얘가 베이스가 되어서 처리해준다.
https://expressjs.com/en/4x/api.html#express.stati
Express 4.x - API Reference
Express 4.x API Note: Express 4.0 requires Node.js 0.10 or higher. express() Creates an Express application. The express() function is a top-level function exported by the express module. var express = require('express') var app = express() Methods express
expressjs.com
(4) Third-party middleware
다른 사람이 만든 미들웨어.
Express 애플리케이션에 다양한 기능을 추가할 수 있다.
- body-parser 미들웨어 사용하기
웹브라우저에서 호스트를 통해 요청한 것은, 청크 단위로 쪼개져서 온다.
그것을 처리하기 위해 req가 올 때마다, 데이터를 계속 배열에 넣어둔 다음 최종적으로 전송이 끝나면 string 형태로 하나로 합쳐서 만들었다.
=> 매번 구현한다면 굉장히 번거로울 것이다. 그것을 쉽게 해주는 것이 body-parser이다.
기본적으로 express.js 안에 포함되어 있기 때문에 설치할 필요는 없다.
실제로 사용하려면 외부 모듈처럼 bodyParser 객체를 만들어서 require한다.
bodyParser.urlencode를 app.use에 등록만 시켜두면, 애플리케이션이 자동으로 호스트 요청 때마다 바디 부분을 처리해서 넘겨준다.
이렇게 줄어든다.
알아서 미들웨어가 body 부분을 처리해서 넣어주기 때문에.
-> 미들웨어를 내가 만들수도 있다.
myLogger이라는 함수를 만든다면, 정해진 형식대로 만들어서 app.use에 등록만 하면 알아서 돌아간다.
형식: function(req, res, next)
app.use(미들웨어 함수)
app.use = 최우선적인 실행.
항상 콘솔창에 로깅되게 된다.
- 단, next()를 호출하지 않는 경우, 흐름이 끊긴다.
=> 서버에 전달된 요청을 처리하는 미들웨어 함수 체인
1) 클라이언트 -> 서버로 요청
3) 미들웨어 요청의 연쇄
4) 라우터를 설정했다면, 라우터에 따라서 결과를 처리
5) 최종적으로 미들웨어에서 요청 전체의 흐름 마무리
체인으로 응답이 만들어진다.
02. 사용자로부터의 데이터 추출
- POST 요청에서, 요청의 body를 통해.
- URL에서의 쿼리스트링을 통해.
1. POST 요청에서, 요청의 body를 통해.
body-parser을 이용해, URL-encoded + json 함수를 사용한다.
둘 다 등록만 하고 있다.
urlencoded -> extended: false
extended가 false라면, 내부 쿼리스트링이라는 모듈을 사용한다.
true인 경우, 내부 qs 모듈을 사용한다.
출력의 결과만 다를 뿐, 매우 차이가 나지 않아서 어떻게 하든 상관없다.
- json <-> urlenconded 둘은 기본적으로 함께 사용한다.
1) json: json 형태의 데이터를 해석한다.
2) urlenconded: url로 enconded된 형태의 데이터를 변환한다.
-> HTML의 form 태그도 host로 전달된다.
내가 입력한 텍스트, 샘플, 제출되면 그 값이 들어간 상태로 서버쪽에 전달된다. 이때 json 형태로 전달되지 않고, x-www-form-urlencoded로 전달된다.
-> 받는 쪽에서 타입을 받아야 데이터를 해석할 수 있는데, 다음과 같은 형태로 전달된다. json 형태가 아니기 때문에, 해석할 수 있는 미들웨어 함수가 요구된다.
=> post 요청에서, 요청의 body를 통해 파생된 결과가 출력된다.
curl --data "firstname=Jon&lastname=Wexler"
http://localhost:80
둘 다 선언만 해놓으면, 아무것도 할 필요 없이 접근만 하면 된다.
2. URL에서의 쿼리스트링을 통해
http://<IP주소>?cart=3&pagesVisited=4&utcode=837623
- 사용자 장바구니에 있는 아이템의 개수
- 페이지 방문 횟수
- 마케팅 코드
바디, 쿼리스트링을 해석, 추출해 사용한다.
3. MVC 아키텍처
'강의 정리 > 서버시스템 구축 실습' 카테고리의 다른 글
서버시스템구축실습 (9) 데이터베이스 연결 (0) | 2024.05.14 |
---|---|
서버시스템구축실습 (6) Node.js 기초 (2) (1) | 2024.05.03 |
서버시스템구축실습 (6) Node.js 기초 (1) (0) | 2024.04.25 |
서버시스템구축실습 (4) 자바스크립트 기초 (0) | 2024.04.02 |
서버시스템구축실습 (2) 웹서버와 데이터베이스 개요 (0) | 2024.03.19 |