Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

10/28 update #12

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions Apr/2024-04-24.md

This file was deleted.

112 changes: 112 additions & 0 deletions Oct/2024-10-28.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
## 날짜: 2024-10-28

### 스크럼

- 학습 목표 1 : 100-hours-a-week 레포 생성 및 코드 이전
- 학습 목표 2 : exprees.js 서버 만들어보기
- 학습 목표 3 : exprees.js HTTP 메서드 짜보기

### 새로 배운 내용

#### 주제 : express 미들웨어

- express 미들웨어란?
Express 미들웨어는 요청(request)과 응답(response) 사이에서 동작하는 함수이다. 또한 그 다음 미들웨어 함수에 대한 액세스 권한도 가지고 있는데 next()를 이용해서 다음 흐름을 가져간다. 실수로 next()를 호출하지 않으면 프로세스가 멈춰버린다.

express 애플리케이션은 기본적으로 "일련의 미들웨어 함수 호출"이다.

- 왜 미들웨어를 사용하는가?
일반 함수로 구현

```javascropt
// 일반 함수들
function checkLogin(token) {
if (!token) throw new Error('로그인 필요');
}

function checkAdmin(role) {
if (role !== 'admin') throw new Error('관리자만 접근 가능');
}

// 라우트에서 사용
app.get('/admin', async (req, res) => {
try {
// 모든 체크 로직을 직접 호출
checkLogin(req.headers.token);
checkAdmin(req.headers.role);
res.send('관리자 페이지');
} catch (error) {
res.status(401).send(error.message);
}
});
```

미들웨어로 구현

```javascropt
// 미들웨어
const loginCheck = (req, res, next) => {
if (!req.headers.token) {
return res.status(401).send('로그인 필요');
}
next();
};

const adminCheck = (req, res, next) => {
if (req.headers.role !== 'admin') {
return res.status(401).send('관리자만 접근 가능');
}
next();
};

// 라우트에서 사용
app.get('/admin', loginCheck, adminCheck, (req, res) => {
res.send('관리자 페이지');
});
```

핵심 차이:

- 일반 함수: 개발자가 직접 함수를 호출하고 에러를 처리
- 미들웨어: Express가 순차적으로 실행하고 에러 처리도 담당
IoC를 통해서 Express가 제어함. 즉, next()를 호출하는 시점에서 Express에게 위임함

#### 주제 : express-rate-limit 모듈 카운트

```javascript
// rate-limit 미들웨어 설정
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15분
limit: 15, // IP당 15회 -> 근데 실제로 왜 8번 때 제한?
message: "Too many requests from this IP, please try again later",
standardHeaders: true, // RateLimit-* 헤더 포함
legacyHeaders: false, // X-RateLimit-* 헤더 비활성화
})
);
```

해당 미들웨어 함수 코드를 넣어서 실행하면 실제로 15번이 아니고 8번 때 제한이 걸린다.
그래서 로깅을 통해서 실제로 요청이 몇 번 오는지 찍어보았다.

```javascript
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
});
```

```text
2024-10-28T08:20:06.253Z - GET /public/css/index.css
2024-10-28T08:20:07.266Z - GET /
```

한번 요청을 보낼 때 이렇게 css까지 포함해서 get 요청을 두번 보내는 것을 알 수 있었다!

### 오늘의 회고

express는 익숙한 spring과 사용 방식이 조금 달라서 배울게 많았다 특히 "미들웨어"라는 개념이 너무 와닫지가 않아서 팀원 한명과 오랫동안 토론했던 기억이 남는다.

### 참고 자료 및 링크

- [middleware DOCS](https://expressjs.com/ko/guide/using-middleware.html)
117 changes: 117 additions & 0 deletions Oct/2024-10-30.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
## 날짜: 2024-10-30

### 스크럼

- 학습 목표 1 : TIL 작성
- 학습 목표 2 : exprees.js 프론트 백 서버 나누기
- 학습 목표 3 : 프론트와 백 연결하여 데이터 주고 받기

### 새로 배운 내용

#### 주제 : 브라우저와 웹 서버 통신

브라우저와 서버가 어떻게 통신하는지 시간 순으로 정리해보겠습니다~!

# 1. 요청 보내기

사용자가 주소창에 URL 입력, 링크 클릭, 폼 제출을 한다.

# 2. DNS 조회

DNS(**Domain Name System)**란 도메인을 ip로 변환해주는 시스템이다.

원래는 주소창에 “93.184.216.34”와 같이 ip 주소를 쳐야하지만 우리는 해당 숫자들을 모두 기억하기 힘들다 그래서 해당 ip와 매핑되는 일종의 alias(별명) 문자열를 만드는데 이것이 도메인 주소인 것이다.

![image.png](image.png)

도메인은 우리가 흔히 아는 www.google.com이며 이는 네트워크 레벨에서 ip 주소로 변환되어야만 한다. 그래서 DNS 서버에 먼저 등록된 alias가 있는지 먼저 요청을 보내고 해당 매핑 값이 있으면 받은 ip 주소로 Web Server에 보내게 된다.

만약에 특정 사이트를 한 번도 방문한 적이 없다면 DNS 서버에 조회를 한다. DNS 서버 안에 네임 서버에 레코드를 저장하여 일정 기간 동안 캐싱합니다. 이후 조회에서는 네임 서버에 쿼리를 먼저 날려 캐싱된 데이터를 확인합니다.

![image.png](image-1.png)

![alt text](image-2.png)

# 3. TCP 3 way handshaking, TLS(**Transport Layer Security)**

HTTPS 통신에서는 TCP 소켓 연결을 통해 서버와 클라이언트가 통신합니다.
3 way handshaking는 SYN, SYN-ACK, ACK로 진행 됩니다.

![alt text](image-3.png)

순서를 보면 그림과 같이 할 수 있습니다. 실제로 데이터를 받기 전에 3번의 3 way handshaking이 진행됩니다. 이후에 중간에 제 3자에 의해서 해독될 수 없게 3번의 추가적인 보완 확인을 합니다.

# 4. 응답

연결이 완료 되면 브라우저는 HTTP GET 요청을 날립니다. 서버는 관련 응답 헤더와 함꼐 HTTP 프로토콜로 body에 HTML을 넣어서 응답하게 됩니다. 응답을 보낼 때 14kb씩 청크해서 보냅니다. 응답 시간을 극도로 빠르게 하기 위해서 랜딩 페이지를 14kb 이하로 만드는 트릭도 있습니다.

# 5. 혼잡제어 / TCP 슬로우 스타트

TCP는 전송 중에 세그먼트로 분리되어 전송됩니다. TCP 헤더에 데이터 순서에 대한 정보가 있기 때문에 분리해서 매 순간 최적의 네트워크 경로로 분리되어 데이터가 보내지게 됩니다. 모두 도착하면 브라우저는 조립하기 시작합니다.

세그먼트 중간 중간 마다 서버는 클라이언트로 부터 ACK 패킷 형태로 승인을 받아야 합니다. 만약 하나의 세그먼트 마다 승인을 받으면 오버헤드가 커질 것이고 한번에 많은 세그먼트를 보내면 사용량 많은 네트워크에서 클라이언트가 세그먼트를 받을 수 없어 계속 ACK 응답만 하게 되고, 서버는 재전송만 하게 될 것입니다.

이를 극복하기 위해 TCP 슬로우 스타트 알고리즘을 사용합니다. 최대 네트워크 대역폭이 결정될 때까지 전송되는 데이터의 양을 점차적으로 늘리고 네트워크 부하가 높은 경우 전송되는 데이터의 양을 줄입니다.ACK이 수신되면 혼잡 윈도우(CWND)의 값이 두 배로 증가하여 서버는 다음에 더 많은 세그먼트를 보낼 수 있게 됩니다. 반대로 ACK이 수신되지 않으면 혼잡 윈도우(CWND)의 값이 반으로 줄어듭니다. 이러한 메커니즘은 너무 많은 세그먼트를 보내거나 너무 적게 보내는 것 사이의 균형을 맞추게 합니다.

즉, 동적으로 윈도우를 조절하게 됩니다.

# 6. 구문 분석

브라우저가 첫 번째 데이터의 청크를 받으면, 수신된 정보를 구문 분석하기 시작합니다. [구문 분석](https://developer.mozilla.org/ko/docs/Glossary/Speculative_parsing)은 브라우저가 네트워크를 통해 받은 데이터를 [DOM](https://developer.mozilla.org/ko/docs/Glossary/DOM)이나 [CSSOM](https://developer.mozilla.org/ko/docs/Glossary/CSSOM)으로 바꾸는 단계입니다. 이는 렌더러가 화면에 페이지를 그리는데 사용됩니다.

요청된 HTML 페이지의 크기가 초기 패킷의 크기인 14kb 보다 크더라도, 브라우저는 구문 분석을 시작하고 가지고 있는 데이터 수준에서 렌더링을 시도합니다. 이것이 웹 성능 최적화에서 브라우저가 페이지를 렌더링 하는데 필요한 모든 것, 아니면 적어도 페이지의 템플릿(첫 렌더링에 필요한 HTML이나 CSS)만이라도 첫 14kb에 포함해야하는 이유입니다. 하지만 화면에 렌더링하기 전에 HTML, CSS, Javascript를 구문 분석해야 합니다.

# 7. DOM 트리 구축

![alt text](image-4.png)

첫 단계는 HTML을 처리하여 DOM 트리를 만드는 것입니다. HTML 구문 분석은 [토큰화](https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList)와 트리 생성을 포함합니다. HTML 토큰은 시작 및 종료 태그 그리고 속성 이름 및 값을 포함합니다. 구문 분석기는 토큰화된 입력을 분석하여 DOM 트리를 만듭니다.

[html](https://developer.mozilla.org/ko/docs/Glossary/HTML) 요소는 시작하는 태그이고 DOM 트리의 루트 노드입니다. 트리는 다른 태그간의 관계와 계층을 반영합니다. 다른 태그에 감싸져 있는 태그는 자식 노드입니다.

구문 분석기가 이미지와 같은 논 블로킹 자원을 발견하면, 브라우저는 해당 자원을 요청하고 분석을 계속합니다. 구문 분석은 CSS 파일을 만났을 때도 지속될 수 있습니다. 하지만 [`async`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function)나 `defer` 같은 설정이 되어있지 않은 `<script>` 태그는 렌더링을 막고, HTML의 분석을 중지시킵니다.

# 8. 프리로드 스캐너

브라우저가 DOM 트리를 만드는 프로세스는 메인 쓰레드를 차지합니다. 그렇기 때문에, *프리로드 스캐너* 는 사용 가능한 컨텐츠를 분석하고 CSS나 Javscript, 웹 폰트 같이 우선순위가 높은 자원을 요청합니다. 프리로드 스캐너 덕에 구문 분석기가 외부 자원에 대한 참조를 찾아 요청하기까지 기다리지 않아도 됩니다. 프리로드 스캐너가 자원을 뒤에서 미리 요청합니다. 그래서 구문 분석기가 요청되는 자원에 다다를 때 쯤이면 이미 그 자원들을 전송받고 있거나 이미 전송받은 후일 것입니다. 프리로드 스캐너가 제공하는 최적화는 블록킹을 줄여줍니다.

```html
<link rel="stylesheet" src="styles.css" />
<script src="myscript.js" async></script>
<img src="myimage.jpg" alt="image description" />
<script src="anotherscript.js" async></script>
```

이 예제에서 메인 쓰레드가 HTML과 CSS를 분석하고 있을 때, 프리로드 스캐너는 스크립트와 이미지를 찾아 다운로드하기 시작할 것입니다. Javascript의 분석과 실행 순서가 중요하지 않고 스크립트가 프로세스를 막지 않도록 하려면 `async` 속성이나 `defer` 속성을 추가하세요.

# 9. CSSOM 구축

중요한 렌더링 경로에서 두 번째 단계는 CSS를 처리하고 CSSOM 트리를 만드는 것입니다.

CSSOM 트리는 사용자 에이전트의 스타일 시트를 포함합니다. 브라우저는 노드에 적용 가능한 가장 일반적인 규칙부터 적용합니다. 그리고 재귀적으로 더 구체적으로 적용된 규칙에 따라 계산된 스타일을 수정해갑니다. 다른 말로, 속성 값을 캐스케이드합니다.

# 10. Javascript 컴파일

CSS가 분석되고 CSSOM이 생성되는 동안, 프리 스캐너 덕에 Javascript 파일 같은 다른 자원도 다운로드 됩니다. Javascript는 해석, 컴파일, 구문 분석 및 실행됩니다. 스크립트는 추상 구문 트리로 구문 분석됩니다.

브라우저의 JavaScript 엔진(Chrome에서는 V8 엔진)이 이 파일을 컴파일합니다.

**파싱**: 다운로드한 JavaScript 코드를 토큰으로 나누고, 구문 분석을 통해 추상 구문 트리(AST)로 변환합니다.

**컴파일**: AST를 바이트코드 또는 기계어 코드로 변환합니다. V8 엔진은 Just-In-Time (JIT) 컴파일 방식을 사용하여, 필요할 때 즉시 컴파일하여 실행합니다.

# 11. 렌더

렌더링 과정에는 스타일, 레이아웃, 페인트 그리고 때때로 합성이 포함됩니다. CSSOM과 DOM 트리는 구문 분석되는 과정에서 생성되고 렌더 트리로 합성됩니다. 렌더 트리는 보이는 요소의 레이아웃을 계산을 합니다. 그러고 나서 요소가 화면에 페인트됩니다. 어떤 경우에는 컨텐츠가 자신만의 레이어를 가지도록 조작되고, 나중에 합성됩니다. 화면의 일부분을 CPU 대신 GPU가 그리면서 메인 쓰레드의 부담이 줄고 성능이 향상됩니다.

# 12. 레이아웃

처음 노드의 사이즈와 위치가 결정되는 것을 *레이아웃* 이라고 부릅니다. 이후에 노드의 크기와 위치를 다시 계산하는 것은 *리플로우* 라고 부릅니다. 예제에서, 첫 레이아웃이 이미지가 오기 전에 일어난다고 가정을 해봅시다. 이미지의 크기를 선언하지 않았기 때문에, 이미지 크기를 알게 된 이후 리플로우가 한 번 있을 것입니다.

### 오늘의 회고

오늘 딥 다이브 한 내용을 참고하였다.

### 참고 자료 및 링크

- [웹페이지를 표시한다는 것](https://developer.mozilla.org/ko/docs/Web/Performance/How_browsers_work)
20 changes: 2 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,6 @@

## 오늘 내가 배운 것들(Today I Learned)

### [4월 첫째주, 1주차] : html, css
### [2주차] : express.js

24.04.05 세부 주제 4 작성 (상세 내역 링크)

24.04.04 세부 주제 3 작성 (상세 내역 링크)

24.04.03 세부 주제 2 작성 (상세 내역 링크)

24.04.02 세부 주제 1 작성 (상세 내역 링크)

### [n월 n째주, n주차] : 간략 주제 작성

yy.mm.dd 세부 주제 4 작성 (상세 내역 링크)

yy.mm.dd 세부 주제 3 작성 (상세 내역 링크)

yy.mm.dd 세부 주제 2 작성 (상세 내역 링크)

yy.mm.dd 세부 주제 1 작성 ([상세 내역 링크](https://github.com/kakao-cloud-edu-5/til-template/blob/main/Jan/yyyy-mm-dd))
24.10.28 미들웨어, rate-limit 모듈 카운팅 ([상세 내역 링크](Oct/2024-10-28.md)) </br>24.10.30 브라우저와 웹 서버 통신 ([상세 내역 링크](Oct/2024-10-30.md))
Binary file added img/image-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/image-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/image-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/image-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.