Modern_Web
Express Application 은 기본적으로 일련의 Middleware 함수 호출입니다.
Express Middleware
-
등록된 순서대로 실행됩니다.
-
함수, 즉 안에서 어떤 작업이든 가능합니다.
-
request 객체, response 객체, next 함수를 인자로 받습니다.
-
request 객체, response 객체를 조작해서 기능 구현합니다.
-
다음 미들웨어를 동작시키기 위해 next 함수를 인자 없이 호출합니다.
(호출을 안하면 해당 요청은 정지된 채로 방치됩니다.)
Middleware 가 하는 일
- 모든 코드를 실행합니다.
- 요청 및 응답 오브젝트에 대한 변경을 실행합니다.
- 요청-응답 주기를 종료합니다.
- 스택 내의 그 다음 미들웨어를 호출합니다.
Middleware 로 하는 일
-
로깅 (morgan)
-
HTTP body 를 객체로 변환 (body-parser)
-
사용자 인증 (passport)
-
권한 관리 (express-stormpath)
const secret = req.query.secret || req.body.secret;
if (secret !== process.env.SECRET) {
res.status(403);
res.send("403 Forbidden");
} else {
next(); // 다음 미들 웨어로 과정을 넘긴다.
}
- ETC..
왜 Middleware 를 사용하는가?
미들웨어로 할 수 있는 모든 일은 라우트 핸들러에서도 할 수 있으나,
여러 라우터에서 사용해야 하는 기능을 중복 작성하는 불편을 덜고
코드를 재사용하기 위해 미들웨어를 사용하는 것입니다.
Middleware 생태계
- 다양한 기능의 Middleware 들이 주로 모여있는 곳입니다.
https://www.npmjs.com/search?q=express%20middleware&page=3&perPage=20
https://expressjs.com/ko/resources/middleware.html
미들웨어 VS 라우트 핸들러
- 라우트 핸들러도 미들웨어입니다. (Express 의 거진 모든 것이 미들웨어)
- 즉, next 함수를 인자로 받는 것이 가능합니다.
app.get("/", (req, res, next) => {
if (!someCondition) {
next(); // 요청을 처리를 하지 않고 다른 핸들러로 넘김
} else {
res.send("hello");
}
});
app.use
- 미들웨어를 앱 전체에서 동작하도록 주입할 때
app.use(helloMiddleware);
- 특정 경로에서만 동작하도록 주입할 때
app.use("/some-path", helloMiddleware);
- 한 번에 여러 개 주입할 때
app.use(middleware1, middleware2, middleware3, ...)
Express 오류 처리
Express 는 내장된 오류 핸들러와 함께 제공되며, 내장 오류 핸들러는 앱에서 발생할 수 있는 모든 오류를 처리합니다.
이러한 기본 오류 처리 미들웨어 함수는 미들웨어 함수 스택의 끝에 추가됩니다.
next()로 오류를 전달하지만 오류 핸들러에서 해당 오류를 처리하지 않는 경우,
기본 제공 오류 핸들러가 해당 오류를 처리하며, 해당 오류는 클라이언트에 스택 추적과 함께 기록됩니다.
스택 추적은 프로덕션 환경에 포함되어 있지 않습니다.
응답의 기록을 시작한 후에 오류가 있는 next()를 호출하는 경우(예: 응답을 클라이언트로 스트리밍하는 중에 오류가 발생하는 경우),
Express 의 기본 오류 핸들러는 해당 연결을 닫고 해당 요청을 처리하지 않습니다.
따라서 사용자 정의 오류 핸들러를 추가할 때,
헤더가 이미 클라이언트로 전송된 경우에는 다음과 같이 Express 내의 기본 오류 처리 메커니즘에 위임해야 합니다.
function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render("error", { error: err });
}
Cookie
쿠키는 클라이언트 로컬(웹 브라우저)에 저장되는 키와 값이 들어있는 작은 데이터 파일입니다.
쿠키에는 이름, 값, 만료날짜(쿠키 저장지간), 경로 정보, 접근 권한등 다양한 옵션이 들어있습니다.
쿠키는 일정시간동안 데이터를 저장할 수 있습니다. (로그인 상태 유지에 활용합니다.)
쿠키는 클라이언트의 상태 정보를 로컬에 저장했다가 참조합니다.
쿠키 전송 절차
- 서버는 브라우저에 저장하고 싶은 정보를 응답과 같이 실어 보낸다 (Set-Cookie 헤더)
HTTP/1.1 200 OK
Set-Cookie: cookieName=cookieValue; Secure; Max-Age=60000
...
- 브라우저는 같은 서버에 요청이 일어날 때마다 해당 정보를 요청에 같이 실어서 서버에 보낸다 (Cookie 헤더)
GET / HTTP/1.1
Cookie: cookieName=cookieValue; anotherName=anotherValue
...
Set Cookie Option
- Expires, Max-Age : 쿠키의 지속 시간 설정을 할 수 있습니다.
- Secure : HTTPS 를 통해서만 쿠키가 전송되도록 설정할 수 있습니다.
- HttpOnly : 자바스크립트에서 쿠키를 읽지 못하도록 설정할 수 있습니다.
- Domain, Path : 쿠키의 scope 설정합니다. (쿠키가 전송되는 URL 을 제한합니다.)
Express + Cookie
-
쿠키 읽기 - req.cookies
요청에 실려온 쿠키가 객체로 변환되어 req.cookies 에 저장됩니다. (cookie-parser 미들웨어 필요합니다.)
-
쿠키 쓰기 - res.cookie(name, value)
쿠키의 생성 혹은 수정합니다.
JavaScript + Cookie
자바스크립트로도 쿠키를 읽고 쓰는 방법이 존재하지만,
보안 상 문제를 일으킬 수 있으므로 이런 접근 방식은 거의 사용되지 않는다.
자바스크립트에서 쿠키에 접근하지 못하도록 HttpOnly 를 항상 설정하는 것이 제일 좋습니다.
쿠키의 한계점
- US-ASCII 밖에 저장하지 못합니다. 보통 percent encoding 을 사용합니다.
- 4000 바이트 내외(영문 4000 자, percent encoding 된 한글 444 자 가량)밖에 저장하지 못합니다.
- 브라우저에 저장됩니다. 즉, 여러 브라우저에 걸쳐 공유되어야 하는 정보,
혹은 웹 브라우저가 아닌 클라이언트(모바일 앱)에 저장되어야 하는 정보를 다루기에는 부적절합니다.
웹개발 방식 - 알고가기
전통적 웹개발 방식 - 요청시마다 새로고침이 일어나며 페이지가 로딩될때마다 서버로부터
리소스들을 전달받아 해석한뒤 화면에 렌더링 하게 됩니다.
현대적 웹개발 방식 - 캐싱과 압축이라는 방식으로 어느정도 해소하였지만 결국 브라우저는
모든 CSS, 자바스크립트, HTML 을 해석한 뒤에 이들을 화면에 렌더링합니다.
Ajax
비동기적인 웹 어플리케이션의 제작을 위한 클라이언트 측 웹 개발 기법이였으나
요즘에는 의미가 변형되어 웹 브라우저에서 XMLHttpRequest 혹은
fetch 를 이용해서 보내는 HTTP 요청을 통칭하기도 합니다.
Ajax model
Ajax 의 장점
- 화면 전체를 다시 로드하지 않고도 내용을 갱신할 수 있어 더 나은 사용자 경험 제공합니다.
- 서버의 응답을 기다리는 동안에도 여전히 웹 어플리케이션을 사용 가능합니다.
- 필요한 자원만 서버에서 받아오게 되므로 트래픽이 줄어듭니다.
Ajax 의 단점
- 클라이언트 구현이 굉장히 복잡해졌습니다. (일이 복잡..)
Axios
- Promise based HTTP client
- 브라우저와 Node.js 에서 모두 사용 가능합니다.
- XMLHttpRequest, fetch 에 비해 사용하기 편하고 기능이 더 많습니다.
Axios Method
- patch : 자료의 일부내용만 변경하고 싶을 때 사용합니다.
- put : 자료 전체를 교체하고 싶을 때 사용합니다.
- post : post 방식의 전송을 할 수 있습니다.
- get : get 방식의 전송을 할 수 있습니다.
// config 객체
axios
.get("/api/todos", {
params: {
// query string
title: "react 공부"
},
headers: {
// 요청 헤더
"X-Api-Key": "my-api-key"
},
timeout: 1000 // 1초 이내에 응답이 오지 않으면 에러로 간주
})
.then(res => {
prettyPrint(res.data);
});
// axios 요청 메소드의 두 번째 인자로 config 객체를 넘길 수 있습니다.
// config 객체를 통해 요청의 쿼리 스트링, 요청 헤더, 쿠키 포함 여부 등 많은 것들을 설정할 수 있습니다.
- delete : 해당 자료를 삭제하고 싶을 때 사용합니다.
Json-Server
아무 보안도 없고, 실무에서 사용하지 못하지만,
간단히 백엔드 기능이 필요할 때 사용하는 것이 좋습니다.
- Plural routes (복수)
GET / posts;
GET / posts / 1;
POST / posts;
PUT / posts / 1;
PATCH / posts / 1;
DELETE / posts / 1;
- Singular routes (단수)
GET /profile
POST /profile
PUT /profile
PATCH /profile
GET /profile
- Filter - Query String 을 이용해서 필요한 정보를 확인할 수 있습니다.
GET /posts?title=json-server&author=typicode
GET /posts?id=1&id=2
GET /comments?author.name=typicode
- Paginate - 페이지 별로 정보를 확인할 수 있습니다.
_page 를 사용하고 선택적으로 _limit 을 사용하여 반환 된 데이터를 매김합니다.
링크 헤더에서 첫 번째, 이전, 다음 및 마지막 링크를 얻을 수 있습니다.
GET /posts?_page=7
GET /posts?_page=7&_limit=20
기본적으로 10 개의 항목이 반환됩니다.
- Sort -
_sort
와_order
를 더해주면 정보를 정렬할 수 있습니다.
기본값은 오름차순입니다.
GET /posts?_sort=views&_order=asc
GET /posts/1/comments?_sort=votes&_order=asc
여러 필드일 경우
GET /posts?_sort=user,views&_order=desc,asc
- Slice -
_start
와_end
,_limit
을 더해주면 정보를 잘라서 볼 수 있습니다.
X-Total-Count 헤더가 응답에 포함됩니다.
GET /posts?_start=20&_end=30
GET /posts/1/comments?_start=20&_end=30
GET /posts/1/comments?_start=20&_limit=10
Array.slice 와 똑같이 작동합니다 (예 : _start 가 포함되고 _end 만 포함).
- Operators - 범위를 가져 오기 위해
_gte
,_lte
를 추가하면 됩니다.
GET /posts?views_gte=10&views_lte=20
_ne
를 사용하면 값을 배재합니다.
GET /posts?id_ne=1
_like
를 사용하면 필터를 할 수 있습니다. (정규표현식도 지원합니다.)
GET /posts?title_like=server
- Full-text search -
q
를 더해주면 텍스트와 일치하는 정보를 검색할 수 있습니다.
GET /posts?q=internet
- Relationships - childeren 리소스를 포함하려면
_embed
를 추가하면됩니다.
GET /posts?_embed=comments
GET /posts/1?_embed=comments
parent 리소스를 포함하려면 _embed
를 추가하면됩니다.
GET /comments?_expand=post
GET /comments/1?_expand=post
중첩 된 리소스를 가져 오거나 만들려면 (기본적으로 한 수준에서는 추가 경로를 추가하십시오)
GET /posts/1/comments
POST /posts/1/comments
Json-Server Tip
{
"todos": [
{
"id": 1,
/* json 서버에 들어가는 객체는 아이디는 다 적어주도록 하자 */
"content": "할 일 텍스트",
"complete": false
}
]
}
Same-origin Policy (동일 출처 정책)
-
웹페이지에서 리소스를 불러올 때, 리소스의 출처가 웹페이지의 출처와 같으면 안전하다고 보고,
출처가 다르면 해당 리소스는 안전하지 않다고 보는 원칙입니다. -
여기서 ‘출처’란 ‘프로토콜 + 도메인 + 포트번호’의 결합을 가리킵니다.
즉, 세 개가 다 같아야 동일 출처라고 할 수 있고, 셋 중에 하나라도 다르면 동일 출처로 간주되지 않습니다. -
웹 보안의 기본 원칙으로, 웹 브라우저의 많은 요소에 적용됩니다.
Same-origin Policy 실습 - 1
const child = window.open("http://www.fastcampus.co.kr");
// 새로 열린 웹 페이지의 콘솔에서
window.foo = "bar";
// 이전 웹 페이지의 콘솔에서
child.foo;
// 출처가 같다면 접근 가능, 아니면 불가
Content-Security-Policy
Content-Security-Policy 헤더를 이용하면,
동일하지 않은 출처에 대한 리소스를 불러올지 말지 결정할 수 있습니다.
CORS (Cross-Origin Resource Sharing)
-
클라이언트 측 cross-origin 요청을
안전하게 보낼 수 있는 방법을 정한 표준입니다. -
쉽게 말하면, 스크립트가 전혀 다른 출처를 갖는 API 서버를
사용하려고 하는 상황에서는 뭔가 추가적인 처리를 해주어야 합니다.
Cross-origin 요청의 위험성
아래 상황을 가정해봅시다.
mywebsite.com 에서 서비스 중인 웹 사이트는 mywebsite.com/api 에서
REST API 를 통해 필요한 정보를 얻습니다.
mywebsite.com/api 경로에 대한 인증은 쿠키로 이루어지고 있습니다.
그런데 만약 evil.com 웹 사이트의 스크립트에서
mywebsite.com API 에 요청을 마음대로 보낼 수 있다면,
이미 my-website.com 도메인에 대해 브라우저에 저장된 쿠키를
이용해서 API 를 마음대로 호출할 수 있을 것입니다.
Cross-origin 요청
- IE8 이상의 모던 웹 브라우저는 cross-origin 요청에 대해 여러가지 제한을 두고 있습니다.
- cross-origin 요청을 허용하려면, 서버가 특별한 형태의 응답을 전송해야 합니다.
- 만약 서버가 cross-origin 요청을 허용하지 않으면, 웹 브라우저는 에러를 발생시킵니다.
CORS 에 관여하는 응답 헤더
- Access-Control-Allow-Origin
- Access-Control-Expose-Headers
- Access-Control-Max-Age
- Access-Control-Allow-Credentials
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
CORS 에 관여하는 요청 헤더
- Origin
- Access-Control-Request-Method (preflighted 전용)
- Access-Control-Request-Headers (preflighted 전용)
CORS - Safe, Unsafe
GET, HEAD 요청은 safe(읽기 전용)이기 때문에 서버에 요청이 도달한다고 해서
서버의 상태에 영향을 미칠 일은 없으므로, 웹 브라우저는 일단 해당 요청을 보내봅니다.
만약 서버가 cross-origin 요청을 허용한다고 응답하면 응답을 그대로 사용하고, 그렇지 않으면 에러를 냅니다.
POST, PUT, PATCH, DELETE 등의 메소드는 요청이 서버에 전송되는 것 자체가 위험하므로,
실제 요청을 보내기 전에 서버가 cross-origin 요청을 허용하는지를 알아보기 위해 시험적으로 요청을 한 번 보내봅니다.
이 요청을 preflighted request 라고 합니다.
(단, 기존 HTML form 의 동작방식인 application/x-www-form-urlencoded 혹은
multipart/form-data 형태의 POST 요청은 preflighted request 가 발생하지 않습니다.)
CORS with credentials
cross-origin 요청에는 기본적으로 쿠키가 포함되지 않으나,
XMLHttpRequest 혹은 fetch 를 통해서 요청을 보낼 때
쿠키를 포함시키는 옵션을 줄 수 있고 이 때 CORS 요건이 더 엄격해집니다.
(Access-Control-Allow-Credentials 헤더 설정 필요하며, Access-Control-Allow-Origin 헤더에 와일드카드 허용 안됩니다.)
복잡하면 그냥…
- 프론트엔드와 API 서버를 같은 도메인으로 제공합니다.
- 불가피하게 둘을 다른 도메인으로 제공해야 한다면
- CORS 를 허용합니다 (cors 미들웨어를 사용하면 간단함)
- CORS 를 허용하는 경우, 쿠키를 쓸 수는 있으나 보안 상 허점이 생기기 쉽고
사용하기도 불편하므로 보통 JWT 와 같은 토큰 방식의 인증을 사용합니다.
쿠키의 단점
- 쿠키를 지원하는 클라이언트에서밖에 사용할 수 없습니다.
- 적절히 관리되지 않은 쿠키는 보안에 취약하며, 관리를 하려고 해도 CORS 대응이 복잡합니다.
Token Based Auth
- 토큰이란, 사용자의 자격증명(아이디, 패스워드 등)을 통해 인증이 이루어진 후, 특정 자원에 대한 자격증명으로서 대신 사용되는 인증 수단
- 서버에 요청을 할 때마다 토큰을 요청에 직접 포함시켜서 전송합니다. (주로 Authorization 헤더에 넣어서 전송합니다.)
Cookie VS Token
토큰 사용의 장점
-
다양한 인증 수단(전화번호, 공인인증서, 생체정보 등)의 인증 결과를
토큰이라는 하나의 수단으로 통일할 수 있습니다. -
쿠키를 지원하지 않는 클라이언트에서도 편하게 사용할 수 있습니다.
-
쿠키를 사용하지 않음으로써 CORS 관련 문제를 회피할 수 있습니다.
토큰 사용의 단점
- 매 요청에 토큰이 포함되게 되므로 적당히 짧은 길이를 유지해야 합니다.
- 토큰 유출에 대한 대비책이 필요합니다. (토큰에 유효기간을 두거나, 유출된 토큰을 강제로 무효화하는 등의 방법을 사용합니다.)
- 쿠키와는 다르게, 클라이언트 개발자가 직접 토큰을 저장하고 관리해야 합니다.
Web Storage
- 브라우저에서 키-값 쌍을 저장할 수 있는 저장소
- 쿠키에 비해 사용하기 편리하고 저장 가능한 용량도 큽니다.(10MB 가량)
- 브라우저 탭이 닫히면 내용이 삭제되는 sessionStorage(임시 저장소)
- 브라우저 탭이 닫혀도 내용이 유지되는 localStrage 가 있습니다.
Local Storage && Session Storage && Cookie
보안 상 주의사항
- (당연히) HTTPS 를 사용해야 합니다. (해킹방지)
- 토큰을 localStorage 에 저장하게 되면 자바스크립트로 토큰을 탈취할 수 있게 되므로, 웹사이트에 악성 스크립트를 삽입하는 공격(XSS)에 노출되지 않도록 신경써야 합니다.
JSON Web Token
- 최근 널리 사용되고 있는 토큰 형식의 표준입니다.
- 토큰 안에 JSON 형식으로 정보를 저장합니다.
- 보안을 위해 서명 또는 암호화를 사용할 수 있습니다.
JWT 실습
// 토큰 받아오기
let token;
axios
.post("/auth", {
username: "fast",
password: "campus"
})
.then(res => {
token = res.data.token;
console.log(`token: ${token}`);
});
// 토큰으로 요청하기 1
axios
.get("/auth", {
headers: {
Authorization: `Bearer ${token}`
}
})
.then(res => {
prettyPrint(res.data);
});
// 토큰으로 요청하기 2
axios
.get("/some-api", {
headers: {
Authorization: `Bearer ${token}`
}
})
.then(res => {
prettyPrint(res.data);
});
// 토큰으로 요청하기 3
axios
.post("/count", null, {
headers: {
Authorization: `Bearer ${token}`
}
})
.then(res => {
prettyPrint(res.data);
});
// Axios는 중복된 설정을 하지 않도록 해주는 편의도구를 제공하고 있습니다.
// 그것을 Axios instance라고 부르는데,
// 한 번 config 객체를 넘겨서 Axios instance를 생성하면 해당 instance를 통해 보내는 요청에는 config 객체가 자동으로 설정됩니다.
// Axios.create
const authedAxios = axios.create({
headers: {
Authorization: `Bearer ${token}`
}
});
authedAxios.get("/auth").then(res => {
prettyPrint(res.data);
});
authedAxios.get("/some-api").then(res => {
prettyPrint(res.data);
});
authedAxios.post("/count").then(res => {
prettyPrint(res.data);
});
Fetch API
- 웹 브라우저의 XMLHttpRequest 를 대체하기 위해 만들어진 새로운 HTTP client 표준입니다.
- 비교적 최근에 도입되어 IE 및 구형 안드로이드 브라우저(4.x)는 지원하지 않습니다.
- Fetch Polyfill (https://github.com/github/fetch)
- isomorphic-fetch (https://www.npmjs.com/package/isomorphic-fetch)
Axios vs Fetch API
Axios 는 여러 편의기능(instance 와 같이 설정을 재사용하거나 요청중인 연결을 취소하는 등)을 제공합니다.
다만, Axios 는 내부적으로 XMLHttpRequest 를 사용하고 있는데 Service Worker 등의 최신 기술이 XMLHttpRequest 를 지원하지 않으므로,
Service Worker 를 사용할 예정에 있는 프로젝트에서는 Axios 대신 Fetch API 를 사용해야만 합니다.
Service Worker 공부해보기
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ko
PWA 도 공부해보기
https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=ko
Cache
컴퓨터 분야에서의 캐시는 (주로 접근 속도의 개선을 위해) 데이터를 미리 복사해 놓는
임시 저장소, 혹은 그 임시 저장소에 데이터를 저장하는 행위를 가리킵니다.
‘cache’ 혹은 ‘caching’이라는 용어 자체는 특정 기술을 가리키는 것이 아니라,
접근 속도를 개선하기 위해 따로 저장소를 두는 ‘방법’을 가리킵니다.
컴퓨터의 아주 많은 부분(CPU, GPU, HDD, 네트워크, 웹, 데이터베이스…)에서 사용되고 있습니다.
HTTP Cache
- 자원의 효율적 로딩을 위한 웹 표준입니다.
- 서버에서 가져온 자원(HTML, CSS, JS, 이미지, …)을 가까운 곳(브라우저, 혹은 다른 서버)에 저장해놓고 재사용합니다.
- 캐시를 할 것인지 말 것인지, 어떻게 할 것인지를 결정하는 규칙이 복잡하고, 브라우저마다 조금씩 다릅니다.
-
Expiration (만료) - 정해진 시간이 지나면 캐시가 자동으로 삭제되도록 설정합니다. (업데이트가 필요없이 지금 이대로 영원히 불변할 파일들은 만료를 무한대로 지정하여 사용할 수 있습니다.)
-
Validation (검증) - 서버에 요청을 보내서 캐시를 계속 사용할 수 있는지 확인하빈다.
Cache 관련 헤더
- Cache-Control
(요청, 응답) 캐시와 관련된 다양한 기능을 하는 지시자를 포함. no-cache, max-age 가 많이 사용됩니다. no-cache, max-age=0 지시자는 캐시를 사용하지 않도록 하거나, 캐시를 아직도 쓸 수 있는지 검증하기 위해 사용됩니다. (각각의 자세한 의미)
- ETag
(응답) 캐시의 검증을 위해 사용되는 자원의 식별자. 주로 자원의 해시값이 사용되나, 마지막으로 수정된 시각, 혹은 버전 넘버를 사용하기도 합니다
해시
해시 함수(hash function)는 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수입니다.
해시 함수에 의해 얻어지는 값은 해시 값, 해시 코드, 해시 체크섬 또는 간단하게 해시라고 합니다.
해시의 특징
- 값이 조금이라도 변하면 JWT 와는 다르게 결과값이 완전히 달라집니다. (입력값이 다르면 출력값도 다릅니다.)
- 입력값의 길이가 얼마가 되었든 출력은 그 길이가 항상 일정합니다.
- x 로부터 h(x)의 값은 얻기 쉽지만 h(x)에서 x 를 구하기는 힘듭니다. (1-wayness 성질을 지닙니다.)
- Expires
(응답) 캐시를 만료시킬 시각을 서버에서 명시적으로 지정합니다.
- Last-Modified
(응답) 원래 자료가 마지막으로 수정된 시각입니다.
- If-None-Match
(요청) 검증을 위해 사용됩니다. 이전에 저장해두었던 자원의 ETag 값을 If-None-Match 헤더의 값으로
요청에 포함시켜서 보내면, 서버는 해당 경로에 있는 자원의 ETag 와 비교해보고 자원의 전송 여부를 결정합니다.
- If-Modified-Since
(요청) 검증을 위해 사용됩니다. 이전에 저장해두었던 자원의 Last-Modified 값을
If-Modified-Since 헤더의 값으로 요청에 포함시켜서 보내면, 서버는
해당 경로에 있는 자원의 Last-Modified 와 비교해보고 자원의 전송 여부를 결정합니다.
아래처럼 엮어서 씁니다.
[ETag] - [If-None-Match]
[Last-Modified] - [If-Modified-Since]
Cacheable Methods
POST 메소드는 Cacheable 범주에 포함되기는 하지만,
특별한 조건을 만족시켜야 하며 실무에서는 POST chace 가 거의 사용되지 않습니다.
캐시의 사용
- 브라우저는 이미 캐시를 잘 활용하도록 만들어져 있습니다.
- Express 는 이미 캐시를 잘 활용하도록 만들어져 있습니다.
- Netlify 는 이미 캐시를 잘 활용하도록 만들어져 있습니다.
일단은 별다른 추가작업 없이도 편하게 캐시 기능을 사용할 수 있지만
우리가 원하는대로 캐시가 동작하지 않을 때 그 원인을 파악하기 위해
캐시 관련 헤더는 숙지해두는 것이 좋습니다.
그리고 HTTP method 를 용도에 맞게 사용하는 것도 중요합니다.
REST API 의 단점
-
각각의 자원마다 경로가 따로 있습니다. 즉, 여러 자원이 동시에 필요한 경우에는 요청을 여러 번 보내야 합니다. (요청의 횟수 면에서 비효율적입니다.)
-
(보통의 경우) 자원의 필요한 속성만 얻어올 수 없습니다. 즉, 일부 속성의 필요하더라도 전체 속성을 가져와야만 합니다. (요청의 용량 면에서 비효율적입니다.)
GraphQL
- Facebook 에서 2015 년 공개한 데이터 질의 언어입니다.
- REST API 를 대체하기 위해 만들어졌습니다.
- 클라이언트에서 필요한 데이터의 구조를 GraphQL 언어로 정의한 후 질의할 수 있고, 서버는 그에 맞게 구조화된 데이터를 응답합니다.
- 서버에서는 GraphQL 질의를 해석하기 위해 별도의 해석기가 필요하며, 여러 언어의 구현체가 나와있는 상태입니다.
2. Today I Found Out
한 주동안 백엔드 쪽에 대해서 공부를 해보았는데
처음은 어렵다가도 하나씩 차근차근 이해를 하려고 노력할수록
이해가 되어서 오늘 있었던 cookie, session, ajax, axios등..
크게 어렵지 않게 이해를 할 수 있었습니다.
하나하나 체인처럼 연결되어 있어 이해할수록 재미가 있습니다.
3. refer
https://fds9.github.io/fds-nodejs-http/
http://vuejs.kr/update/2017/01/04/http-request-with-axios/
https://wpsn-axios-example.glitch.me/
http://jeong-pro.tistory.com/80