라우터에 대해 알아보고 Node.js와 Express를 사용하여 짠 프로그램들을 정리해 보겠다.
박승규 저자의 Node.js 백엔드 개발자 되기 책의 내용을 참고하였다.
라우터(Router)란?
- 라우터는 네트워크에서 데이터를 한 곳에서 다른 곳으로 전달하는 장비 또는 소프트웨어
- 라우터는 인터넷이나 로컬 네트워크에서 컴퓨터, 스마트폰, 서버 등의 장치들 사이에서 데이터를 전송하는 역할을 수행함.
- 데이터 패킷을 이동시키고 목적지까지 최적의 경로를 결정하는 역할을 함.
- 패킷을 분석하여 목적지 주소를 확인하고, 다른 네트워크나 서브넷으로 패킷을 전송함. 이때, 최적의 경로를 선택하여 데이터 전송을 빠르고 안정적으로 이루어지게함.
- 라우터는 여러 개의 인터페이스를 가지고 다른 네트워크와 연결되며, 이러한 인터페이스들을 통해 패킷을 주고받음.
- 인터넷의 경우, 전 세계에 분산된 수많은 라우터들이 연결되어 있으며, 이들이 함께 동작하여 인터넷 데이터의 전송과 라우팅을 담당함. 로컬 네트워크에서도 라우터는 서브넷이나 VLAN(Virtual Local Area Network)을 구분하고, 네트워크간 통신을 관리하는 역할을 수행함.
- 일반적인 웹 서버는 URL 경로에 따라서 다른 응답을 줌(= 라우팅)
- 또한, 라우터는 보안을 위한 방화벽 기능이나 네트워크 주소 변환(NAT, Network Address Translation) 등을 지원하여 네트워크의 보안과 효율성을 높이는 역할도 함.
- Node.js에서 url이라는 모듈을 사용하면 URL 경로를 간단하게 읽을 수 있음.
> URL 구조
http://www.example.com:80/path/to/file.html?key1=value#hash
http => 프로토콜
www.example.com => hostname(도메인명)
80 => 포트 번호
path/to/file.html => pathname(웹 서버 자원에 대한 경로)
?key1=value => query string(웹 서버에서 제공하는 추가 매개변수)
#hash => hash(서버에 전송하지 않는 일종의 북마크)
+) 쿼리 스트링 = HTTP 요청을 보낼때 사용자가 원하는 값을 보내는 방식. 경로값 뒤에 ?를 붙인다음 key=value 형식으로 사용가능. 여러개일 경우 '&'로 구분해서 추가
▷ pathname에 있는 정보를 활용하여 라우터 만들기
- localhost:3000/user와 localhost:3000/feed라는 두개의 URL이 있다고 가정. 두 요청에 대해 다른 응답을 줘보겠다.
http 모듈로 서버 인스턴스를 만들고, url 모듈을 사용해 요청(req)으로 받은 url의 pathname을 얻어낸다.
↳ url이 "localhost:3000/user"라면 pathname으로 "/user"를 가져온다.
조건문에서는 받아온 pathname이 "/user"이냐, "/feed"이냐, 혹은 그 외의 것이냐로 나누어 결과를 세팅해보겠다.
각각 위와 같은 결과가 나온다.
url모듈과 if문만 사용한 간단한 라우터이다. (실제로 프로덕션 레벨에서 사용하는 라우터는 복잡함. 하지만 요청으로 들어온 정보를 분석해서 라우팅하는 방법 자체는 같음)
▷ 위 코드(createServer) 리펙터링하기
- 위의 코드는 요청에 대한 응답을 createServer() 안에서 직접 컨트롤하는데, 이는 createServer() 콜백 함수에 모든 코드를 추가해야하므로 좋지 않음.
- 라우터와 실행하는 함수 부분을 나누어 보겠다.
조건문 내부의 내용을 함수로 만들어 처리했다. → 메인 루틴을 깔끔히 유지하면서도 요청별 함수만 요구사항에 알맞게 변경하면 되는 코드가 됨.
▷ 동적 응답하기
"localhost:3000/user"에 들어갔을때, 고정된 값이 아닌 동적으로 변경되는 응답이 보여지도록 해보겠다.
user 함수를 다음과 같이 바꿔준다.
(주의할점은 end에 넣을 문장에서 큰따옴표가 아닌 그레이브 기호( ` )로 작성한다.)
▷ 라우터 리펙터링하기
- 위의 코드는 if문에서 모든 요청을 분석한다. (함수가 user(), feed(), notFound() 뿐만 아니라 수백개가 넘어간다면 유지보수 문제 생김)
- 함수를 추가할 떄마다 if문에서 실수하지 않도록 조치해야함.
- if문에 사용되는 매개변수가 같은 패턴을 보일 때는 맵 자료구조가 유용함.
- if 문에 (path in urlMap)을 두고 urlMap에 path가 있는지 확인한다.- urlMap[path](req, res); 와 같이 urlMap에 path값으로 매핑된 함수를 실행한다.- 34번 라인에는 urlMap을 정의해준다. 라우터 규칙 매핑 키로 path가 들어가고 값에 함수를 할당한다.- 주의할점은 user함수나 feed 함수들이 정의된 뒤에 urlMap을 정의해 줘야한다. (const로 선언한 변수들은 초기화 전에 읽을 수 없다고함)
+) 호이스팅(hoisting) = 함수, 클래스, 변수를 끌어올려서 선언되기 전에 사용하도록 하는 기능. JavaScript에서는 var로 선언한 것들이 호이스팅이 됨. (즉, 어디서 선언이 되든지 참조 가능)- let, const, 함수 표현식, 클래스 표현식은 호이스팅 되지 않음.
▶ 익스프레스 프레임워크
- 현재까지 Node.js의 기본 라이브러리로 웹 서버를 만들어왔는데, 서비스 가능한 서버이지만 기능이 많이 부족하다.
- 실전에서 사용하는 서버라면 라우터에서 HTTP 메서드로 각각 요청을 받는 기능, 템플릿 엔진 기능, 미들웨어 등의 기능을 제공해야한다.
▷ 웹서버가 일반적으로 제공하는 기능들
⦁ 라우팅
- URL 요청을 함수와 매핑시켜주는 기능
⦁ 정적 파일 서비스
- CSS, JavaScript, 이미지 등의 정적인 파일을 다루는 기능
⦁ 템플릿 엔진
- 동적인 웹 페이지를 HTML과 인스턴스를 사용해 생성하는 기능
⦁ 요청(Request) 데이터 다루기
- HTTP 요청을 추상화하여 편리하게 다룰 수 있게 하는 기능
⦁ 응답(Response) 데이터 다루기
- HTTP 응답을 커스터마이징 할 수 있는 기능. 파일 내려받기, 이미지 출력 등
⦁ 파일 업로드
- HTTP로 전송된 파일을 읽고 다룰 수 있는 기능
⦁ 쿠키 및 세션 지원
- 클라이언트 측 혹은 서버 측의 메모리에 일정 기간 동안 저장해야 하는 데이터를 다루는 기능
⦁ 리다이렉트
- 서버의 응답시 다른 페이지로 전달(redirect)시키는 기능
⦁ 에러 페이지
- 요청이 잘못되었거나, 서버 에러시 특정 에러 페이지를 보여주는 기능
⦁ 미들웨어
- 요청 혹은 응답 사이에 공통된 기능을 추가하는 기능
↳ Node.js에는 위와 같은 기능들을 제공하는 오픈 소스 웹 서버가 많으며 그중 익스프레스가 가장 많이 사용된다고 함.
▷ 익스프레스 설치
적당한 폴더 위치를 만들어서 express를 설치한다.
npm install express 명령 사용(npm = nodejs package manager)
express 패키지를 로딩해 express에 할당한다.
express() 함수 실행으로 express 인스턴스를 만들고 app에 할당한다.
app.get을 사용해 url의 path가 '/'이면서 http 메서드가 get()인 경우 콜백 함수를 실행한다. (인코딩 설정 후 "Hello Express" 출력)
listen 함수를 사용해 클라이언트의 요청을 기다리고, 위에서 정의한 3000 포트를 사용한다.
(익스프레스가 위치한 곳에 파일을 만들어야 동작하는 듯하다.)
▷ Node.js 라이브러리로 만든 서버를 익스프레스로 구현하기
- 위에서 만든 라우터 코드를 Express로 리펙터링 해보겠다.
- Node.js 라이브러리 코드에서의 urlMap으로 url 매핑을 관리하던 부분을 없애고, app.get() 함수에 등록하도록 하였다.
(url 매핑이 많아질 경우 이전보다 편리해지고 깔끔하게 유지할 수 있음)
- res.end() 함수로 화면에 비춰주는 것 대신, res.json() 함수를 사용하여 응답을 JSON 타입으로 보여주며 charset을 utf-8로 자동 설정해주는 기능이 있다.
- const로 선언되어 있던 기능들을 function을 사용하도록 변경하였다. (호이스팅을 사용하기 위함)
- feed의 parameter로 "_" 사용하였다. 이는 사용하지 않는다는 표시이며 사용하지 않는 변수는 빼는 것이 원칙이지만, 함수 인터페이스 구조상 넣을 수 밖에 없을 때 사용하는 관례이다.
▷ 간단한 게시판 만들기
- 익스프레스로 간단한 게시판 API를 만들어 보겠다.
- REST API 원칙을 따른 메모리 기반으로 동작하는 휘발성 게시판을 만든다. (DB x)
↳ REST API = 자원을 URL에 표현하고 자원을 가져오는 행위를 HTTP 메서드로 표현하는 규칙
경로 | HTTP 메서드 | 설명 |
/ | get | 게시판 목록을 불러옴 |
/posts | post | 게시판에 글 작성 글은 id, 제목, 작성자, 내용, 생성일자로 구성 |
/posts/:id | delete | 게시글 아이디가 id인 글을 삭제 |
- express 모듈 받아오고 게시글 리스트로 사용할 posts 배열을 둔다.
- req.body를 사용하기 위해서는 JSON 미들웨어를 사용해야 하는데(사용하지 않으면 undefined 반환됨) app.use() 함수에 express.json()을 넣어 JSON 미들웨어를 활성화 시킨다.
- url 인코딩 설정을 해준다. (body에 Key=Value 조합 형태의 데이터 타입을 위한 설정)
- app.get("/")에는 "/"로 오는 요청에 실행된다. res.json()을 통해 리스트를 JSON 형식으로 보여준다.
- app.post("/posts")는 "/posts"로 요청이 오면 실행되고, HTTP 요청의 body 데이터를 변수에 할당한다. (변수 생김새가 근본없게 생겼다)
- posts의 push() 함수를 통해 새로운 게시글 정보를 리스트에 담아주고 JSON 형식으로 보여준다.
- app.delete("/posts/:id")는 데이터 삭제를 위해 사용할 것이다. 라우팅 규칙에 :id로 표기된 부분은 해당 부분에 데이터가 들어오면 문자열 타입으로 params.id에 할당된다. (스프링 RequestMapping 할 때, "/{id}"와 같다고 보면됨)
const filteredPosts = posts.filter((post) => post.id !== +id);
↳ 이 거지같이 생긴 코드는 글 삭제 로직이다. 게시판의 글에서 id 이외의 글들만 뽑아서 filteredPosts에 재할당한다.
(모던 자바스크립트에서 주로 filter() 함수를 사용하여 배열 요소를 삭제하는 편이라고 함. +id는 문자열인 id를 숫자형으로 변경한다는 뜻이라함😂😂)
- isLengthChanged는 기존 게시판과 필터링된 게시판 글의 길이를 비교하여 게시글 삭제를 판별한다.
- posts에 필터링된 리스트를 담고 판별 결과에 따라 응답을 띄워준다.
그럼 실행시켜 보겠다.
Node.js를 실행시키고 "curl -X GET http://localhost:3000"을 통해 curl로 get 호출한다.
curl -X POST ... 로 값을 넣고, curl localhost:3000으로 값을 확인한다.
로컬에서 띄워도 잘 나오는것을 볼 수있다.
게시글 지우기 명령이다.
id 1번을 처음 지우면 OK 응답과 delete를 수행한다. 두번째는 수행하지 않는다.
지금까지 REST API 게시판을 만들어 보았다.
curl 옵션 몇가지를 정리하고 글 마무리하겠다.
옵션 | 사용 예시 | 설명 |
-X | -X POST | HTTP 메서드 정보 |
-d | -d "key1=value1&key2=value2" localhost:3000 | POST 통신시 body 데이터 |
-H | Content-Type: application/x-www-form-urlencoded | 헤더 정보 |
-x | curl -x http://proxy_server:proxy_port --proxy-user username:password | 프록시 서버 설정 |
-T | curl -T file.txt http://server.com | 파일을 서버에 전송시 사용 |
-A | curl -A "Mozilla/5.0" http://server.com | 유저 에이전트를 변경 |
-i | curl -i https://suldenlion.tistory.com/ | 서버의 응답을 결과로 출력 |
-I | curl -I https://suldenlion.tistory.com/ | 서버 응답에서 헤더 값만 출력 |
-O | curl -O http://server.com/test.txt | 서버의 파일을 이름 변경없이 내려받기 |
-L | curl -L http://server.com/redirectingURL | 리다이렉트 URL 따라가기 |
-s | curl -s localhost:3000 | 에러가 발생해도 출력 x (silent) |
-S | curl -S localhost:3000 | 에러 발생시 에러 출력 o (Show) |
'Node.js' 카테고리의 다른 글
댓글 기능이 있는 게시판 만들기 (Node.js, MongoDB, Express 사용) (0) | 2023.07.31 |
---|---|
MongoDB에 대하여 (0) | 2023.07.30 |
자바스크립트 비동기 처리 정리 (0) | 2023.07.26 |
Node.js에 대하여 (2) | 2023.07.26 |
댓글