Web Server – 기초
node.js를 이용한 백엔드 구축
→ API 서버를 구현하여 Express, 라우팅, Server-side 디버깅 학습
CommonJS
와 모듈
의 개념 학습
학습 목표
*HTTP
- HTTP 요청/응답
- HTTP 의 요청 방식과 응답 코드
* node.js modules의 사용
- node.js의 내장 http 모듈 사용법
- http 모듈 사용시에 서버에 CORS 설정하기
- CommonJS를 이용한 모듈 내보내기/불러오기
* 라우팅과 API
- 라우팅(조건에 따른 분기)을 이해하고, 이를 서버 코드에서 구현
- 클라이언트가 사용할 수 있도록, 서버 API 문서를 직접 작성
* Express 라이브러리
- express 라이브러리에 대한 이해
- 미들웨어의 개념을 이해
* 서버 개발과 디버깅
- CRUD 를 수행하는 웹 서버 개발 방법
- 서버 개발을 돕는 다양한 툴
CORS 리뷰 및 적용
SPA가 등장하고, 웹 앱이 고도화되면서 서버-클라이언트 통신 간에 여러 곳(다른 origin)에 있는 리소스를 활용한 필요가 생김
→ 클라이언트
(브라우저?) 에서는 same origin이 아니라 cross origin 요청을 해야 한다
CORS(Cross Origin Resource Sharing)
cross origin에서 리소스(서버 자원)을 요청하여 사용한다
보안 상의 이유
로 브라우저에서 크로스 도메인 요청은 기본적으로는 제한
되어 있음
→ 웹 애플리케이션 고도화를 위해 개선 요청(개발자들)
→ 서버가 허용한 범위 내에서 cross origin 요청이 허용됨
defaultCorsHeaders 의 내용 예시
* 모든 도메인(*)을 허용한다
* 메소드는 GET POST PUT DELETE OPTIONS 만 허용
* 헤더에는 content-type과 accept만 쓸 수 있다
* preflight request는 10초까지 허용됨
// 이를 코드화 하면 다음과 같다
const defaultCorsHeader = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
'Access-Control-Max-Age': 10 //응답 헤더는 결과를 브라우저 캐시에 캐시 할 수있는 기간을 나타냅니다.
};
OPTIONS 메소드
간단하게, preflight 요청이다
서버에서 Allow 하는 조건들을 다 맞추고 있는가?
→ 사전에 서버에 확인하는 요청(preflight request)
defaultCorsHeaders{
...
access-control-allow-origin: 허용주소.com,
...
}
//이 `화이트 리스트`만 서버에 OPTIONS 요청이 허용 된다
이 OPTIONS 메소드로 CORS 설정과 관련된 부분을 체크한다고 볼 수 있는 듯 싶다?
Node 앱 디버깅 하는 법
postman 앱과 함께 써서 직접 해보자
--inspect 옵션을 통해 디버깅이 가능하다
ex)"scripts": {
"start": "node --inspect server/basic-server.js",
그런데 나는 시작하자마자 디버깅을 걸고싶다?
→ 딱 브레이킹 포인트가 시작지점(처음)부터 걸려있다고 보면된다
→ 옵션: --inspect-brk
"scripts": {
"start": "node --inspect-brk server/basic-server.js",
"test": "echo no test",
노드몬이 다행히 이 옵션들을 다 지원하므로, node→ nodemon으로 바꿔서 쓰면 된다!
HTTP 통신(클라이언트-서버) 관련 보충 내용
<http 요청 메시지의 예>
GET /kimcoding/message http/1.1 // 메소드 /uri http버전
// 요청의 첫줄에는 메소드 uri http 버전이 들어간다
Content-type: application/json //헤더키: 헤더값
// 반드시 한칸 띄우기
payload(body부분)
----------
<http 응답 메시지의 예>
http/1.1 200 ok // http 버전 http 상태 코드
헤더키: 헤더값
// 반드시 한칸 띄우기
body 부분
node.js 공식문서 읽기
node.js 의 공식문서를 참고하여 미니 노드 서버를 만들어 보자
https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction/
http 트랜잭션 해부
공식 문서 내용 중 요청과 응답에 대한 부분만 추려보면,
request.on('data', (chunk)=> { //요청에 data가 왔을때, callback함수를 실행해라~ //이벤트리스너 생각
body.push(chunk);
}).on('end', ()=>{
body=Buffer.concat(body).toString();//body.toString() 과 똑같음
// 여기에 요청바디가 문자열로 담겨있다.
response.writeHead(201, defaultCorsHeader);
console.log(body);
response.end(body.toUpperCase());
})
// .on 은 이벤트라고 생각하면 편하다
chunk란?
buffer를 이름지어준 것. buffer가 데이터 흐름 속에서 하나의 덩어리라서 그냥 인자명을 이름지은 것
크로스 오리진의 기준
크로스 오리진(Cross Origin)을 판별하는 기준에는 다음 아래의 조건이 있다
이 조건이 다르다면 같은 오리진이 아닌 다른 오리진이라는 뜻!
1. 스킴(http, https 같은거)
2. 호스트(localhost, ...)
3. 포트번호(4000,5000, ...)
serve 유틸리티
클라이언트를 서버처럼 띄워주는 유틸리티 이다
npm으로 설치하면 클라이언트를 서버처럼 동작시킬 수 있다
→ 로컬 주소가 아닌 localhost:port 처럼 동작하게 하는 것!
vscode에서 Live Sever 확장 앱을 설치하여 live sever로 동작시키면 같은 원리로 작동하는 듯 싶다
서버 모드로 동작시키면 기존에는 프리플라이트 요청이 건by건으로 동작하던 것이(로컬 모드)
CORS에서 설정한 값('Access-Control-Max-Age': 10)에 따라 해당 age가 지나면 다시 프리플라이트 요청을 날리는 식으로 동작한다
Express를 통한 리팩토링
express 공식 문서
를 보면서 시작하기부터 내용을 실습해 보는 것을 추천한다!
Node.js Express
Express.js는 Node.js 환경에서 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 있는 프레임워크
Express의 장점
1. 미들웨어 추가가 편리
2. 자체 라우터 기능을 제공
Express 설치
다운로드 원하는 폴더 내에서
npm install express --save // 의존성(dependency) 모듈로 설치되도록 설정
라우팅 처리하기
메소드와 URL에 따라 분기(라우팅)하면 된다
//기존 node.js 코드
const requestHandler = (req, res) => {
if(req.url === '/lower') {
if (req.method === 'GET') {
res.end(data)
} else if (req.method === 'POST') {
req.on('data', (req, res) => {
// do something ...
})
}
}
}
이를 express의 라우팅을 활용하면 다음과 같이 직관적 코드가 작성 가능하다
const router = express.Router()
router.get('/lower', (req, res) =>{
res.send(data)
})
router.post('/lower', (req, res) =>{
// do something
})
미들웨어(Middleware)
express의 가장 큰 장점인 미들웨어
→ 일종의 완성된 함수?메소드? 같은 느낌이다
자주 사용하는 미들웨어
미들웨어를 주로 사용하는 상황은 다음과 같다
1. 모든 요청에 대해 url이나 메소드를 확인할 때
2. POST 요청 등에 포함된 body(payload)를 구조화할 때(쉽게 얻어내고자 할 때)
3. 모든 요청/응답에 CORS 헤더를 붙여야 할 때
4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때
모든 요청에 대해 url이나 메소드를 확인할 때
xxx.use() 메소드를 사용한다
const express = require('express');
const app = express();
const myLogger = function (req, res, next) {
console.log('LOGGED'); // 이 부분을 req, res 객체를 이용해서 고쳐도 된다
next();
};
app.use(myLogger);
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(3000);
POST 요청 등에 포함된 body(payload)를 구조화할 때
body-parser 미들웨어를 사용하면 간단히 처리 가능하다
→ express 최신버전에는 이 기능이 내장되어 있으므로 안 받아도 된다
내장된 express.json() 메서드를 이용
→ json화시킬때 원시 데이터 타입들도 내용이 나오게 하려면 strict 옵션을 false로 지정해야 한다
만약 일반 text를 요청/응답한다면 express.text() 메서드 사용
const express = require('express');
const server = express();
server.use(express.json({strict: false})); //반드시 strict: false 해줘야 된다!
…(생략)
server.post('/upper', (req, res)=> {
console.log('upper 테스트');
console.log(req.body);
res.json((req.body).toUpperCase());
})
모든 요청/응답에 CORS 헤더를 붙여야 할 때
간단하게 cors 미들웨어를 설치해서 쓰면 간편하다
const cors = require('cors')
// 생략
app.use(cors()) // 모든 요청에 대해 CORS 허용
요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때
로그인 및 권한과 관련된 부분에서 사용한다
// HTTP 요청에서 토큰이 있는지 여부를 판단하여, 있으면, next()하고 없으면 에러(400)를 보냄
app.use((req, res, next) => {
// 토큰의 유무 판단?
if(req.headers.token){
req.isLoggedIn = true;
next()
} else {
res.status(400).send('invalid user')
}
})
express에 대한 보충 내용
- 라우팅: 메소드와 URL(엔드포인트)를 이용해서 분기(routing)점을 만드는 것
- express의 장점
* 라우팅할 때 if 안써도 된다
* body 받기가 편함(미들웨어 사용시)
→ buffer 조합으로 할 필요 x
* cors 적용이 간편(미들웨어 사용시)
→ 즉, 미들웨어 잘 사용하는 게 중요!
- res.send() vs. res.end()
둘 다 비슷해보이나, 데이터 없이 응답할 때는 res.end()를 사용하고,
데이터를 담아서 응답할때는 res.send()를 사용하는 것을 추천함(공식문서)
'SE Bootcamp 내용 정리' 카테고리의 다른 글
react - 컴포넌트 디자인 (0) | 2021.10.28 |
---|---|
Web Server - 서버 만들기 연습 (0) | 2021.10.28 |
react - 데이터 흐름의 이해와 비동기 요청 처리 보충 내용 (0) | 2021.10.21 |
react - 데이터 흐름의 이해와 비동기 요청 처리 1 (0) | 2021.10.21 |
http/네트워크 – REST API & Postman (0) | 2021.10.19 |