Google OAuth 구현 

- Front: React

- Sever: Nextjs

 

Google OAuth를 직접 구현하면서 OAuth의 흐름을 이해하기 위해서 Next-auth 라이브러리를 사용하지 않았다.

 

OAuth는 Client(내 서비스), Resource Owner(내 서비스 이용자), Resource Sever(구글) 간의 통신으로 이루어진다.

 

Google OAuth를 사용하기 위해서는 Google Cloud Platform에서 사용자 인증정보를 등록해야 한다.

 

 

등록을 마치면 client_id, client_secret, redirect_uri 정보를 확인 할 수 있는데 이 값들을 사용해 코드를 구현하면된다.

위의 정보들은 구글 서비스를 이용하는 Client인지 식별하기 위함이라고 이해

 

가장 중요하다고 생각되는 redirect_uri를 설정하면 User가 내서비스에서 구글 로그인을 하겠다고 시도했을때 구글에서 승인한 redirect_uri로 이동을 시켜준다. 

 

중요한건 Google Cloud Platform에 등록된 client_id, client_secret, redirect_uri가 모두 일치해야 구글은 User(내 서비스 이용자)에게 구글 로그인 페이지로 이동시키고, 사용자가 구글 로그인을 승인하면 구글이 redirect_uri로  승인 코드를 전달한다.

여기서 구글이 승인코드를 보내주는건 내 서비스에서 구글 로그인을 사용하겠다고 사용자가 승인했다는 의미의 코드라고 이해

 

 

승인 코드를 프론트에서 확인하고 서버에 request 요청 -> 서버에서는 request 데이터를 분석해 필요한 정보를 담아 구글 서버에 request 요청 -> 승인된 code인지 판별하고 구글에서는 내 서버에 token을 전송

여기서의 token은 구글이 내 서비스를 승인했다고 이해

 

여기까지 완료하면 구글에게 다시 한번 userInfo를 요청하면 된다.(이떄 구글에서 보내준 token 보냄)

 

 

프론트는 React를 사용했고 처음에는 button 태크의 onClick 이벤트를 사용했고 직접 redirect_uri로 window를 이동시켰다.

export default function LoginComponent() {

	const handleLogin = () => {
        const clientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID;
        const redirectUri = process.env.NEXT_PUBLIC_GOOGLE_LOGIN_REDIRECT_URI;

        // authorization code 요청
        const googleAuthUrl =
          `https://accounts.google.com/o/oauth2/v2/auth?` +
          `client_id=${clientId}&` +
          `redirect_uri=${redirectUri}&` +
          `response_type=code&` +
          `scope=email profile&` +
          `access_type=offline&` + // access_type을 스코프가 아닌 URL 파라미터로 설정
          `prompt=consent`; // 권한 승인을 항상 요청하는 옵션
        console.log(googleAuthUrl);
        window.location.href = googleAuthUrl;
  	};
  
  	return (
  		<button onClick={handleLogin}>로그인 with Google</button>
  	)
  }

 

이에 따라 백엔드 nextjs 코드는

import { request } from "http";
export async function GET(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);
    const code = searchParams.get("code");
    if (!code) {
      return NextResponse.json({ message: "인증되지 않은 User 입니다." }, { status: 400 });
    }

    const requestBody = {
      code: code,
      client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
      client_secret: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_SECRET!,
      redirect_uri: process.env.NEXT_PUBLIC_GOOGLE_REDIRECT_URI!,
      redirect_uri: process.env.NEXT_PUBLIC_GOOGLE_LOGIN_REDIRECT_URI!,
      grant_type: "authorization_code",
      access_type: "offline",
    };
    const data = new URLSearchParams(requestBody);
    const sendData = new URLSearchParams(requestBody).toString();

    const tokenResponse = await axios.post("https://oauth2.googleapis.com/token", data.toString(), {
    const tokenResponse = await axios.post("https://oauth2.googleapis.com/token", sendData, {
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
    })
    
    
    ...
    
    return NextResponse.json({})
  }

프론트에서 보낸 요청 중, url을 파싱해 'code' 만 변수로 저장했고,
구글에 승인 요청을 위해 token 요청을 보냈다.

이렇게 했을 떄는 tokenResponse를 확인할 수 있었는데 문제는 그다음이었다...........ㅠ

 


redirect_uri_mismatch....

redirect_uri_mismatch 문제가 발생한건

 

프론트의 코드를 수정하면서 였다.

기존에 구현한 방식은 팝업으로 구글 로그인이 뜨는게 아닌 페이지를 직접 이동시켰기 때문에 서버와의 통신 중에 로딩 페이지를 구현해 보여줘야 한다. 

사실 이걸 어떻게 해야할까 고민하다가 @react-oauth/google을 알게되었,,,,

 

 

useGoogleLogin 도입

export default function LoginComponent() {

	  const googleLogin = useGoogleLogin({
        scope: "email profile",
        onSuccess: async authCode => {
          try {
            const response = await axios.post("/api/auth/login/callback", { authCode: authCode.code });
            console.log(response);
           } catch (err: any) {
            setMessage(err.response.data.message);
          }
        },
        onError: err => console.log(err),
        flow: "auth-code",
      });

  	return (
  		<button onClick={googleLogin}>로그인 with Google</button>
  	)
  }

 

공식 문서에 보면 onSuccess나 onError로 간단하게 구현할 수 있다는걸 확인할 수 있었다.

이걸 바꾸고 서버에서 url을 파싱하는 부분만 수정하면 완료될줄 알았다ㅠㅠㅠㅠㅠㅠㅠ

그땐 몰랐지...4시간이나 삽질하고 GPT랑 싸우고 있을줄은......

확실히 코드는 간결해졌고 따로 로딩 UI를 구현하고 보여주지 않아도 된다고 생각했다.

 

(client_id, clinet_secert, redriect_uri를 설정하지 않아도 자동으로 처리되는 듯...?)

 

그리고 백엔드 코드를 변경했다.

export async function POST(req: NextRequest) {
  try {
    const { authCode } = await req.json();
    if (!authCode) {
      return NextResponse.json({ message: "인증 코드가 없습니다." }, { status: 400 });
    }

    const requestBody = {
      code: authCode,
      client_id: process.env.GOOGLE_CLIENT_ID!,
      client_secret: process.env.GOOGLE_CLIENT_SECRET!,
      grant_type: "authorization_code",
    };

    const tokenResponse = await axios.post("https://oauth2.googleapis.com/token", requestBody, {
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
    });
    
  return NextResponse.json({});
  
}

 

 

url을 파싱할 필요가 없었고 authCode를 콘솔로 찍었을때도 문제가 없었다.....

근데....ㅎ

 

 

redirect_uri_mismatch 에러가 발생했고 구글링해본 결과 대부분은 배포 환경에서 발생하는 문제였기 때문에 관련된 정보를 찾기가 어려웠다.

 

별짓 다해보다가 어떤 글을 봤었는데 구글에서 사용자가 구글 로그인을 승인했을 때 보내주는 승인코드가 백엔드로 들어가는 과정에서 문제가 있었다는 글을 봤다.

 

그래서 백엔드 콘솔에 찍어봤는데

이렇게 code값이 확인되었다.

 

바로 클라이언트 콘솔에서 code값을 찍어봤다.

 

동일한 에러였다

 

구글에서 보내준 코드는 4/로 시작하는데 백엔드에 들어간 code는 / 대신 "%2F"가 들어가 있었고 이걸 인코딩한다고 GPT랑 싸웠다....

그리고 redirect_uri가 문제였기 때문에 백엔드에서 redirect_uri를 확인해봤더니

이 아이도 %를 포함한 문자열이 들어가있었다.

 

근데 결과적으로 다 실패했고

알고보니 원래 구글 token 보낼때 저렇게 변형되어서 들어가는거 같더라...? 이건 확실하지 않음

 

 

다시 구글링.....
진짜 도움되는 글을 하나 찾아 해결 할 수 있었다.

 


해결...

redirect_uri에 postmessage를 넣으라는 글이었다. 참조

프론트와 서버에 각각 redirect_uri를 직접 넣지 않고 postmessage를 넣었더니!!!

 

프론트코드

export default function LoginComponent() {

	  const googleLogin = useGoogleLogin({
        scope: "email profile",
        onSuccess: async authCode => {
          try {
            const response = await axios.post("/api/auth/login/callback", { authCode: authCode.code });
            console.log(response);
           } catch (err: any) {
            setMessage(err.response.data.message);
          }
        },
        onError: err => console.log(err),
        flow: "auth-code",
        redirect_uri: "postmessage",
      });

  	return (
  		<button onClick={googleLogin}>로그인 with Google</button>
  	)
  }

flow 다음에 redirect_uri 추가!

 

백엔드코드

export async function POST(req: NextRequest) {
  try {
    const { authCode } = await req.json();
    if (!authCode) {
      return NextResponse.json({ message: "인증 코드가 없습니다." }, { status: 400 });
    }

    const requestBody = {
      code: authCode,
      client_id: process.env.GOOGLE_CLIENT_ID!,
      client_secret: process.env.GOOGLE_CLIENT_SECRET!,
      grant_type: "authorization_code",
      redirect_uri: "postmessage",
    
    };

    ...
    
  return NextResponse.json({});
  
}

 

 

드디어 해결!!!

 

이렇게 토큰 데이터를 받아왔다*_*

 

 


Reference

https://medium.com/@juhyoung.jung1992/%EB%A6%AC%EB%B9%99%ED%8F%AC%EC%9D%B8%ED%8A%B8-google-oauth-client%EC%97%90%EC%84%9C-%EA%B3%84%EC%86%8D%ED%95%B4%EC%84%9C-400-redirect-uri-mismatch-%EA%B0%80-%EB%82%98%EB%8A%94-%EA%B2%BD%EC%9A%B0-be9a6f737d9b

 

[리빙포인트] google oauth client에서 계속해서 400 redirect_uri_mismatch 가 나는 경우

아티클을 쓰기에는 너무 짧고, 안쓰기엔 아까운 글들을 공유하는 개발 리빙 포인트 시간입니다.

medium.com

 

https://berom.tistory.com/30

 

Goolge OAuth2 로그인 구현 with React

Google Cloud Platform에서 OAuth 설정 먼저하자 구글 클라우드 콘솔에서는 OAuth 동의화면과 사용자 인증 정보를 등록해야 한다. OAuth 동의화면 먼저 OAuth 동의화면에서는 앱 이름, 사용자 지원 이메일과

berom.tistory.com

 

1. 정의

메모리에 올라가 실행중인 프로그램으로 응용프로그램은 프로세스가 아님

응용프로그램이 파일 형태로 저장된 경우 : 코드 이미지 또는 바이너리

 

 

2. 프로세스와 운영체제

운영체제는 응용프로그램을 실행시켜 프로세스를 생성하고 프로세스의 실행, 중단, 종료를 관리

 

3. 프로세스 스케줄링

프로세스 실행과 관련된 운영체제의 기능
어느 시점에 어떤 프로세스를 실행시킬건지에 관련된 규칙들

하나의 프로세스가 실행되는 동안 다른 프로세스는 실행 불가
실행중인 프로세스가 끝날때까지 기다렸다가 다음 프로세스를 실행시켜야 하는 문제가 발생
➲ 스케줄링 등장


1) 배치처리 시스템

자료구조 중 큐(FIFO)를 사용하는 스케쥴링

  • 실행되어야 할 프로세스들을 미리 등록시킴
  • 프로세스의 실행이 종료되면 자동으로 다른 프로세스가 실행됨
  • 사용자가 첫번째 프로세스가 끝났는지 확인할 필요없이 os가 알아서 순차적으로 프로그램을 실행시킴
문제 : 한번에 하나의 프로그램만 실행 가능 & 어떤 프로그램의 실행시간이 길면 다른 프로그램 실행까지의 시간이 오래 걸림

 

 

2) 시분할 시스템

한대의 컴퓨터 계정을 나눠 계정별로 여러 사용자가 사용하는 경우 각 계정별로 쉘이 실행됨
해당 컴퓨터가 배치처리 시스템 스케쥴링을 사용하면 A계정에서 쉘프로그램이 종료되어야만 B계정의 쉘프로그램이 실행
동시 사용이 불가하고 요청을 해도 다른 계정에서 사용중인 경우 응답시간이 지연됨 
➲ 시분할 시스템의 등장
  • 다중 사용자 지원을 위해 컴퓨터 응답 시간을 최소화하는 시스템
  • 시간을 세밀하게 분할하여 하나의 응용 프로그램이 cpu를 점유하는 시간을 잘게 쪼개어 실행될 수 있게 하는 시스템(1/10초)
  • 프로세스 A, B, C가 존재하는 경우 : 프로세스A를 1/10초 실행, 프로세스 B를 1/10초 실행, 프로세스 C를 1/10초 실행후, 다시 프로세스A가 1/10초 실행 => 최소 3/10초 안에 진행됨

 

3) 멀티태스킹 시스템

  • 멀티태스킹 시스템의 구현은 시분할 시스템과 동일(목적이 다름)
  • 단일 CPU에서 여러 응용 프로그램이 동시에 실행되는 것 처럼 보이도록 하는 시스템(단일 CPU에서는 하나의 프로그램만 실행이 가능)
  • 시분할 시스템보다 더 짧은 단위로 실행 응용 프로그램이 바뀜 : 사람이 눈으로는 두 프로세스가 동시에 실행되는 것 처럼 보임


4. 멀티프로그래밍

  • 구현은 시분할시스템, 멀티태스킹과 유사한면이 있으나 목적이 다름
  • CPU를 최대한 많이 사용하고자 하는 시스템
메모리가 계층구조를 가짐에 따라 CPU가 메모리에 접근하는 속도가 달라짐
저장매체(메모리)에 데이터가 저장된 경우,
- case1) 레지스터에 데이터가 있는 경우 CPU가 한 사이클 만에 데이터를 가져와 실행할 수 있음
- case2) HDD에 데이터가 있는 경우 CPU가 데이터를 가져오는 시간이 길어지고, 데이터를 가져오는 동안 다른 작업 없이 대기
  • CPU를 현재 사용할 수 없는 프로그램을 CPU를 바로 사용할 수 있는 프로그램으로 교체해 CPU를 최대한으로 사용
    ex. 파일 열기를 요청한 경우, 열리는 동안 CPU를 사용하지 않기 때문에 그 동안 다른프로그램을 실행시켜 프로세스로 만들어줌

 

프로그램을 만들 때 성능을 개선하기 위해서는 메모리(코드가 아니라 데이터나 파일을 메모리에서 실행)에서 실행시킬 수 있는 프로그램을 개발
➲ CPU가 접근하는 시간이 짧아지고 성능이 향상됨

 


4. 프로세스 알고리즘

  1. FIFO 스케줄러: 큐에 실행시킬 프로그램을 등록 - 큐에서 등록된 순서대로 프로세스를 실행시키는 알고리즘
  2. SJF 스케줄러 : 우선순위 큐, 최소힙을 사용, 프로세스 실행시간이 가장 짧은 프로세스를 먼저 실행시키는 알고리즘
  3. 우선순위 기반 스케줄러
    • 정적 우선 순위 : 프로세스마다 우선순위를 미리 정함
    • 동적 우선 순위 : 스케줄러가 상황에 따라 동적으로 우선순위를 정함
  4. Roun Robin 스케줄링 알고리즘 : 큐에 실행시킬 프로그램을 순서대로 배치하여 실행 - 일정 시간 동안 프로세스가 완료되지 않으면 종료시킨 후, 큐에 종료된 프로세스를 다시 넣고 다른 프로세스를 실행하는 방식을 반복

 

5. 프로세스 상태정보

  • new(생성) : 프로세스를 생성하는 중인 상태
  • ready(실행가능) : 실행준비 완료
  • running(실행) : CPU에서 실행상태
  • blocked(대기) : 실행이 불가한 상태
  • exit(종료) : 프로세스를 완전히 종료하기 위한 상태

'Dev-log > 운영체제' 카테고리의 다른 글

운영체제  (0) 2024.08.08
핵심적인 기능을 하는 커널과 부가적인 기능을 하는 여러 프로그램이 합쳐져 있는 시스템 소프트웨어


1. 정의

  • 시스템 자원(하드웨어)들을 효율적으로 관리
  • 사용자와 하드웨어 사이의 인터페이스를 제공
  • 응용프로그램(운영체제위에서 돌아가는 프로그램)이 원활하게 동작하도록 지원하는 시스템 소프트웨어



2. 목적(시스템 자원을 관리하고, 응용프로그램을 관리하는 이유)

사용자가 사용하는 응용프로그램이 적절하게 동작하도록 지원
=> 응용프로그램이 CPU를 독점하거나 반복실행하게 만들 수 있음 => 사용자가 원하는 응용프로그램이 적절하게 동작할 수 없음 



3. OS의 역할

Q. 응용프로그램이 하드웨어에 직접 접근하지 않는다면 어떻게 하드웨어 자원을 사용할 수 있을까?
A. 운영체제가 필요한 자원을 응용프로그램에게 할당
  • 프로세스 관리  : 프로세스 생성과 종료
  • 자원 접근과 할당
    1. CPU : CPU는 한번에 하나의 프로세스를 실행 -> 다른 프로세스가 CPU를 사용하기 위해 기다려야 하는데 이때 운영체제에서 스케줄링을 처리
    2. 메모리 : 프로세스의 크기 등을 고려하여 메모리의 어떤 주소에 적재할지 결정
    3. 입출력장치 : CPU에 인터럽트 요청 신호를 보내면 CPU는 커널 영역에 있는 인터럽트 서비스 루틴을 실행
  • 파일시스템 관리


4. shell(쉘)

  • 사용자가 하드웨어를 조작할 수 있도록 인터페이스를 제공하는 프로그램
  • CLI와 GUI 환경으로 분류
  • 명력을 해석, 명령을 실행(커널에 명령을 전달하기 위해서는 커널이 이해할 수 있는 언어로 전달해야함)



5. kernel(커널)

  • 하드웨어를 관리하는 OS의 핵심(핵심 서비스를 담당)으로 OS의 가장 아래 계층에서 돌아감
  • 커널 위에 여러 소프트웨어 계층을 올린 것
  • 하드웨어 자원을 필요한 프로세스에 나눠줌 : 프로세스 제어, 메모리 제어, 프로그램이 운영 체제에 요구하는 시스템 콜 등을 수행
  • 사용자가 실행하는 응용프로그램이 하드웨어 자원에 직접 접근하는 것을 방지하여 자원을 보호
    (응용프로그램이 자원에 직접 접근하여 조작하면 자원이 무분별하게 관리되고 하드웨어 전체에 악영향을 끼칠 수 있음)
사용자 인터페이스 미지원 : 사용자와 컴퓨터의 상호작용은 지원하지 않음 (운영체제는 인터페이스를 제공, 커널에는 포함되지 않음)



6. 이중 모드(사용자 모드 - 커널 모드)

CPU가 명령어를 실행하는 모드를 사용자 모드와 커널 모드로 구분하는 방식
CPU에 명령어와 CPU Protection Ring의 level 정보가 같이 전달되고, level 정보에 따라서 실행 여부가 결정됨

 

  1. 사용자 모드 (level 3)
    • 운영체제의 서비스를 제공받을 수 없는 실행 모드
    •  커널 영역의 코드를 실행할 수 없는 모드
  2. 커널 모드 (level 0)
    • 운영체제 서비스를 제공 받을 수 있는 실행 모드
    • 커널 영역의 코드를 실행할 수 있는 모드
    • CPU가 커널 모드로 명령어를 실행하면 자원에 접근하는 명령어를 포함한 모든 명령어를 실행할 수 있음



7. 시스템 콜

  1. 정의
    • 쉘과 커널이 커뮤니케이션 하기 위한 인터페이스
    • 사용자모드에서 커널모드로 전환하기 위한 요청으로 소프트웨어 인터럽트(인터럽트를 발생시키는 특정 명령어에 의해 발생)
  2. 동작과정
    • 사용자가 쉘을 사용해 명령을 하면 쉘은 커널에 요청을 하고 요청 결과를 쉘프로그램으로 전달, 쉘은 사용자가 요청 결과를 볼 수 있게 화면에 처리
    • 응용프로그램 실행 과정에서 운영체제 서비스를 빈번하게 이용 → 시스템콜이 빈번하게 발생하고 사용자 모드와 커널 모드를 오가며 응용프로그램이 실행됨
  3. 특징
    •  운영체제별로 시스템콜을 호출할 수 있는 API 구현이 다름(시스템콜도 운영체제별로 다름)

 

8. 시스템 콜 발생 후

  1. CPU
    • 진행중이던 작업을 백업하고 커널 영역 내에 시스템 콜을 수행하는 코드를 실행
    • 운영체제 코드를 실행한 후 다시 기존에 진행하던 응용프로그램으로 복귀해 작업을 실행
  2. 운영체제
    • 응용프로그램 대신 자원에 접근하여 요청한 작업을 대신 수행(완료후 다시 사용자모드)

 

 

Reference

https://hongong.hanbit.co.kr/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%9E%80-%EC%BB%A4%EB%84%90%EC%9D%98-%EA%B0%9C%EB%85%90-%EC%9D%91%EC%9A%A9-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%8B%A4%ED%96%89%EC%9D%84-%EC%9C%84%ED%95%9C/
https://namu.wiki/w/%EC%BB%A4%EB%84%90(%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C)

'Dev-log > 운영체제' 카테고리의 다른 글

프로세스 & 프로세스 스케줄링  (0) 2024.08.11

1. lazy loading 사용 목적

React는 서버로 데이터를 요청 & JavaScript 파일로 로딩됨

  • React에서 import문이 다 처리되어야 최종적으로 사용자에게 보여줄 화면을 그릴 수 있음
  • 라우트와 컴포넌트가 많아질 수록 모든 파일을 불러오는데 시간이 소요됨 -> 사용자 경험과 연관 문제 발생
lazy loading은 특정 컴포넌트의 로딩을 지연시키는 것
= 로딩을 지연시켜서 특정 컴포넌트를 필요시에 불러오는 것

 


특정 컴포넌트에 사용자가 방문했을때만 해당 코드가 다운되도록 처리하면 자바스크립트 파일 로딩 시간을 단축시킬 수 있음

React로 만들어진 웹페이지에서 App 컴포넌트를 화면에 렌더하기 위해서 App 컴포넌트에

import된 변수, 함수, 클래스, 컴포넌트 등이 모두 처리되어야 함(상호 의존관계) => 첫 페이지의 로딩속도가 느려짐

 

 

 

2. lazy loading 사용 방법

1. React의 라우팅을 정의한 곳에서 불러오는 import문을 제거
2. import문을 제거하지 않을 경우 페이지 로딩시 마다 import문이 자동으로 처리된 후 최종적으로 화면에 렌더
3. React.lazy로 컴포넌트 재설정 : React.lazy(() => import('/path/yourComponent')

  • React.lazy는 동적 import()를 호출하는 함수를 인자로 가짐
    • import('경로')는 프로미스를 반환
    • React.lazy는 프로미스를 받아 내부적으로 처리
    • 프로미스가 해결되면(=모듈이 로드되면) React.lazy는 동적으로 import된 모듈의 export default를 가져와 컴포넌트로 사용 

4. Suspense 컴포넌트로 래핑

  • Suspense 컴포넌트는 일부 컴포넌트가 아직 렌더링할 준비가 되지 않은 경우 로딩중임을 나타낼 수 있게 해줌
  • Suspense 컴포넌트의 fallback 속성을 사용해 로딩중일때 보여줄 컴포넌트를 설정

5. 확인

  • 개발자도구 - 네트워크 탭 : 해당 페이지를 방문하면 자바스크립트 파일이 동적으로 다운로드 된것을 확인
  • 메인 페이지 접속시에는 lazy loading 처리된 페이지가 네트워크에서 로드하지 않음

 

3. 코드 적용

기존코드(lazy loading 적용전)

import React from "react";
import { Routes, Route } from "react-router-dom";
import CartView from "../components/carts/CartView";



const Router = (): JSX.Element => {
  return (
    <Routes>
      <Route path="/cart" element={<CartView />} />
    </Routes>
  );
};

export default memo(Router);

 

 

lazyloading 적용 후 코드

import React, { Suspense } from "react";
import { Routes, Route } from "react-router-dom";

const CartViewLazyLoading = React.lazy(() => import("../components/carts/CartView"));

const Router = (): JSX.Element => {
  return (
    <Routes>
      <Route
        path="/cart"
        element={
          <Suspense fallback={<div>Loading...</div>}>
            <CartViewLazyLoading />
          </Suspense>
        }
    </Routes>
  );
};

export default memo(Router);

 

 

간단하게 Suspense 컴포넌트와 React.lazy()를 사용해 lazy loading을 적용

 

 

4. 결과

 

React.lazy()를 처리한 후 메인 페이지에서 CartView 컴포넌트를 로딩하지 않는 것을 확인할 수 있음

 

 

 



Reference

https://ko.legacy.reactjs.org/docs/code-splitting.html
https://velog.io/@ksa199653/React-%EC%A7%80%EC%97%B0%EB%A1%9C%EB%94%A9lazy-loading

1. 정의

  • 클럭 : 컴퓨터에서 논리상태인 0(Low)과 1(High)이 일정한 간격으로 반복되는 신호
    • 제어장치가 클럭 신호를 받아들임
    • cpu가 일정시간(신호를 받을때)마다 명령을 실행
  • 클럭 사이클 : Low와 High가 일정 주기로 반복되는 현상(0과 1을 반복)
  • 클럭 주기 : 클럭 사이클이 한번 도는데 걸리는 시간, 항상 동일(Low에서 High까지 걸리는 시간)

 

2. 클럭의 level, trigger, edge

  1. level : 클럭 신호에서의 Low와 High 
  2. trigger :  Higt(1)  또는 Low(0)로 변화하게 만드는 신호 
    • 레벨을 변화시키는 신호
    • 0인 상태에서 트리거 발생시 1로 변화
  3. edge : 0에서 1이 되거나, 1에서 0이 되는 상태를 구분하는 것으로 2가지 종류를 가짐
    • rising edge
    • falling edge

 

3. 클럭 신호와 Latch & 클럭신호와 Flip-flop

  • Latch : 클럭 신호를 level에서 감지 
  • Flip-flop : 클럭신호를 edge에서 감지

4. 래치, 플립플롭

1) 정의 

래치와 플립플롭 모두, 1비트 또는 바이너리 데이터(이진데이터)를 저장할 수 있는 조합 논리 회로

 

2) RS래치(Reset-Set)

NOR게이트를 2개 조합한 회로로 클럭신호 없이 입력되는 순간 바로 반영

NOR게이트를 2개 조합한 회로에 S와 R 입력값을 받을 수 있도록 구성

S와 R이 모두 1인 경우는 없으며, S 또는 R이 1인 경우만 존재

 

  • [case1] S = 1
    • S가 1인 경우, NOR게이트에 의해 Q'는 0
    • R은 0인 상태에서 Q'가 0으로 들어오면서 NOR게이트에 의해 Q는 1
  • [case2] R = 1
    • R이 1인 경우 NOR게이트에 의해 Q는 0
    • S는 0인 상태에서 Q가 0으로 들어오면서 NOR게이트에 의해 Q'는 1
Q와 Q'가 S, R과 함께 입력으로 전달됨 -> 출력이 입력으로 전달되는 구조 떄문에 이전 값을 저장할 수 있게 된다.
처음 S, R값을 입력한 후 S, R값을 다시 0으로 만들어도 이전 값을 기억!

 

3) RS 플립플롭

AND게이트와 NOR게이트를 2개 조합한 회로로 클럭신호를 반영(RS래치에서 클럭이 연결된 구조)

  • RS래치와 다르게 CP(Clock Pulse) 신호를 받아 동작
    • CP : 규칙적으로 발생하는 전기 신호
  • AND게이트로 연결되기 때문에 R과 S는 CP가 1일때만 동작이 가능
  • Q와 Q'는 서로 반대되는 값을 가짐 
0일때는 1로 바꾸고, 1일때는 0으로 바꾸는 두가지 기능을 가지는 논리회로

 

 

4) D-type 플립플롭

R/S의 두개의 Input을 Data라는 하나의 input으로 변경하고, NOT게이트를 추가

  • 입력신호 D가 NOT게이트를 통과하기 때문에 R/S와 마찬가지로 input이 동시에 1이 될수 없게 제한
    • 회로적으로 차단
  • D-type 플립플롭은 입력 D의 값을 클럭의 엣지에서 확인해 Q에 반영
    • 엣지가 발생하지 않는 시간에는 Q가 변하지 않고 유지됨
    • 엣지는 rising-edge와 falling edge를 사용
  • AND게이트를 사용하고 있기 때문에 클럭이 1의 신호를 보낼때만 RS래치가 정상적으로 작동!
    • 0의 신호를 보내는 경우에는 데이터가 저장되지 않으(래치가 작동하지 않음)

Reference

 

[컴퓨터 공학] RS플립플롭(RS래치2)

전에 RS래치의 전구가 이어져 있는 버젼에서 회로를 다음과 같이 바꿔보자.앞서 말했듯이 이 회로는 S가 1이었던 것을 Q가 기억하는 회로이다. 이러한 메모리 기능을 특정 순간에만 사용하기 위

velog.io

 

D 플립플롭

  D Flip-flop, Data Flip-flop, Delay Flip-flop   D 플립플롭(2022-08-16)

www.ktword.co.kr

 

'Dev-log > 컴퓨터구조' 카테고리의 다른 글

반가산기 전가산기  (1) 2024.06.09
비트와 논리연산  (0) 2024.06.09
컴퓨 구조  (0) 2024.06.04

1. 반가산기(Half-adder)

2입력 2출력의 구조로, 두 입력값을 더하여 합과 캐리를 산출하는 논리회로

 

1) 반가산기 입력 및 출력 결과

 

2)  반가산기 특징

2진수에서 입력된 두 값이 1, 1인 경우

  • sum의 값은 0
    • sum은 두 이진수를 더했을때 2 이상이 되는 경우 0으로 처리하고, carry로 1을 넘겨줌
  • carry의 값은 1
    • carry는 자리올림값

 

3) sum을 만족하는 논리회로 : XOR게이트

  • 배타적 OR게이트의 약어(배타적인 입력상태에서만 출력이 1)
  • 논리식 : A'B + AB' = A+B
  • 두개의 입력 신호가 같으면 '0'을 출력, 다르면 1을 출력

 

4) carry를 만족하는 논리회로 : AND게이트

  • 논리식 : AB

 

5) 결론 : XOR게이트와 AND로 이진수의 반가산기 회로 구성

출처 : 위키피디아


2. 전가산기

반가산기 2개로 전가산기를 구성
3입력 2출력 구조로, carry를 포함하여 덧셈 연산을 수행(두입력값 외어 이전 연산에서 생긴 carry까지 더해줌)

 

1) 전가산기 입력 및 출력 결과

 

2) 전가산기 회로도


3. n비트 가산기

n비트 가산기 : 전가산기 n개를 조합하여 구성

 

1) 고속가산기(Ripple Carry Adder)

전가산기를 조합하여 만든 가산기

  • 4비트 가산기
    • 전가산기 4개를 조합하면 4비트 가산기를 만들 수 있고, 16(2⁴)개의 숫자 계산 가능
    • 입력값 a, b가 4비트로 들어오고, Cout을 포함하면 5비트로 출력됨
carry가 입력값으로 들어오기 때문에 carry가 계산되어 전달될때까지 상위비트는 대기 상태
-> 딜레이 발생 -> 연산 속도의 저하

 

논리회로로 계산이 가능

 

 

 

Reference

https://homubee.tistory.com/43

https://ko.wikipedia.org/wiki/%EA%B0%80%EC%82%B0%EA%B8%B0

https://velog.io/@tonyhan18/%EB%94%94%EC%A7%80%ED%84%B8-%ED%9A%8C%EB%A1%9C-%EA%B0%9C%EB%A1%A0-12

 

'Dev-log > 컴퓨터구조' 카테고리의 다른 글

클럭과 플립플롭  (0) 2024.06.11
비트와 논리연산  (0) 2024.06.09
컴퓨 구조  (0) 2024.06.04

1. 비트 

1) 구성 및 특징

  • 0 또는 1의 값을 나타내는 이진수
  • 컴퓨터는 비트를 사용해 연산을 수행
  • 컴퓨터의 가장 작은 단위

2) 비트로 나타낼 수 있는 수

복수의 비트를 하나의 단위로 간주하여 각 비트가 지니는 0 또는 1의 값과 위치를 기준으로 2진법 체계의 값을 나타낼 수 있음
  • 1 비트로 나타낼 수 있는 십진수(2¹개) : 0과 1

  • 2비트로 나태낼 수 있는 십진수(2²개) : 0~3

  • 8비트(=1바이트)로 나타낼 수 있는 십진수(2⁸개)

2. 논리연산

컴퓨터에서 데이터를 처리하는데 사용되는 연산으로 주로, 비트 단위로 연산

논리게이트(AND, OR, XOR, NOT 등)를 사용하여 연산을 수행

 

1) AND 게이트

 

 

2) OR 게이트

 

 

3)  NOT게이트

- input : 1개

 

 

 

 


 

 

4) NAND 게이트 : AND게이트와 NOT게이트가 연결된 것

 

 

5)  NOR게이트 : OR게이트와 NOT게이트가 연결된 것


3. 부울대수식

George Boole이 개발
논리연산을 수학적 수식으로 표현하는 방법을 제공

 

 

Reference

https://bugoverdose.github.io/computer-science/bit-and-logic-operation/

https://ko.wikipedia.org/wiki/AND_%EA%B2%8C%EC%9D%B4%ED%8A%B8

https://ko.wikipedia.org/wiki/NOR_%EA%B2%8C%EC%9D%B4%ED%8A%B8

https://ko.wikipedia.org/wiki/NOT_%EA%B2%8C%EC%9D%B4%ED%8A%B8

https://ko.wikipedia.org/wiki/OR_%EA%B2%8C%EC%9D%B4%ED%8A%B8

https://ko.wikipedia.org/wiki/NAND_%EA%B2%8C%EC%9D%B4%ED%8A%B8

https://ko.wikipedia.org/wiki/NOR_%EA%B2%8C%EC%9D%B4%ED%8A%B8

'Dev-log > 컴퓨터구조' 카테고리의 다른 글

클럭과 플립플롭  (0) 2024.06.11
반가산기 전가산기  (1) 2024.06.09
컴퓨 구조  (0) 2024.06.04

1.  폰노이만 구조

출처 : 위키피디아

  1. 구성
    • 중앙처리장치(CPU), 메모리 , 프로그램
    • 메모리 : 프로그램 영역(명령어) + 데이터 영역
      • 메모리는 저장공간마다 주소를 가지고 있고, 해당 주소들은 명령어 또는 데이터를 저장
      • 명령어 : 실행할 프로그램 코드
      • 데이터 : 프로그램이 처리할 데이터
    • 프로그램 내장 방식(CPU와 메모리를 분리하고 버스를 통해 명령어 읽기, 데이터 읽기, 데이터 쓰기가 가능)
  2. 특징
    • 프로그램을 메모리에서 꺼내 CPU에 전달하여 연산작업을 하고, CPU가 연산작업을 마치면 다시 메모리에 저장
    • 내장 메모리 순차처리 방식 : CPU는 순차적으로 한번에 하나씩 명령어를 실행
    • 하드웨어의 재배치 없이 소프트웨어만 교체
  3. 컴퓨터 동작과정(참고)
    • 제어장치를 통해 메모리에서 명령어를 CPU로 가져오기
      • 읽어온 명령어는 레지스터에 저장
    • 명령어의 해독(decode)
    • 명령어의 실행(execute)

2. 컴퓨터 구성 요소

1. CPU(중앙처리장치)

메모리에 저장된 명령어를 읽고, 해석해 실행
  • 산술논리연산장치(ALU)
    • 산술연산
    • 논리연산
  • 제어장치 : 명령어의 조작을 지시하는 장치
  • 레지스터 : CPU가 연산하는데 필요한 데이터를 임시로 저장하는 기억장치

 

2. Memory(코드와 데이터를 저장)

  • 프로그램의 명령어와 프로그램 수행에 필요한 데이터를 저장
  • 주기억장치
    • CPU 안에 레지스터, 캐쉬
    • 컴퓨터 내부에서 현재 CPU가 처리하고 있는 내용을 저장하고 있는 기억장치
    • 용량이 크고 처리속도가 빠름
    • CPU의 명령에 의해 기억된 장소에 직접 접근하여 읽고 쓸수 있음
      • ROM : 비휘발성 메모리 / Read-only
      • RAM : 휘발성 메모리 / Read and Write, 데이터를 임시저장할때 사용(실행하고 있는 파일은 보조기억장치에 저장해줘야 함)
      • 특정 프로그램이 실행되면 보조기억장치에 저장된 데이터를 주기억장치로 불러와 CPU가 해당 데이터를 처리
  • 보조기억장치(외부 기억장치)
    • 물리적읜 디스크가 연결되어 있는 기억장치
    • 전원을 끄더라도 데이터가 사라지지 않고 영구적으로 보관 가능 
    • SSD, HDD

 

3. IO Devices

  • 입력장치 : 마우스, 키보드
  • 출력장치 : 모니터, 프린터, 스피커

 

컴퓨터의 주요 구성요소를 연결해주는 장치가 BUS

시스템 버스 : 하드웨어 구성 요소를 물리적으로 연결하는 선

 

'Dev-log > 컴퓨터구조' 카테고리의 다른 글

클럭과 플립플롭  (0) 2024.06.11
반가산기 전가산기  (1) 2024.06.09
비트와 논리연산  (0) 2024.06.09

+ Recent posts