<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sungmin-choi.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 26 Feb 2024 09:08:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sungmin-choi.log</title>
            <url>https://images.velog.io/images/sungmin-choi/profile/aa4373b8-1dee-4926-95e7-45de93e71260/KakaoTalk_20210708_175854944.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sungmin-choi.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sungmin-choi" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[AWS SAA] 기타 서비스 1]]></title>
            <link>https://velog.io/@sungmin-choi/AWS-SAA-%EA%B8%B0%ED%83%80-%EC%84%9C%EB%B9%84%EC%8A%A4-1</link>
            <guid>https://velog.io/@sungmin-choi/AWS-SAA-%EA%B8%B0%ED%83%80-%EC%84%9C%EB%B9%84%EC%8A%A4-1</guid>
            <pubDate>Mon, 26 Feb 2024 09:08:30 GMT</pubDate>
            <description><![CDATA[<p>AWS SAA 자격증 준비 과정에서 개인적으로 헷갈렸던 부분들에 대해 집중적으로 정리한 기타 서비스 내용입니다. 개인적인 학습 목적으로 만들어졌기 때문에, 모든 범위를 완벽하게 커버하지는 못할 수 있습니다.</p>
<h2 id="aws-config">AWS Config</h2>
<p>AWS Config는 AWS 계정에 있는 <strong>AWS 리소스의 구성을 자세히 보여</strong> 줍니다. 이러한 보기에는 <strong>리소스 간에 어떤 관계</strong>가 있는지와 <strong>리소스가 과거에 어떻게 구성되었는지도 포함</strong>되므로, 시간이 지나면서 구성과 관계가 어떻게 변하는지 확인할 수 있습니다.</p>
<ul>
<li>AWS Config에서 기록하게 할 리소스 유형을 지정하여 리소스 구성 측정 및 감사 평가 한다.</li>
<li>요청 시 구성 스냅샷 및 구성 기록을 수신하도록 Amazon S3 버킷을 설정합니다.</li>
<li>구성 스트림 알림을 보내도록 Amazon SNS를 설정합니다.</li>
<li>AWS Config에 Amazon S3 버킷 및 Amazon SNS 주제에 액세스하는 데 필요한 권한을 부여합니다.</li>
</ul>
<blockquote>
<p>결론:
AWS 리소스 구성을 측정, 감사 및 평사할 수 있는 서비스입니다. 리소스 구성을 지속적으로 모니터링 및 기록하고 원하는 구성을 기준으로 자동으로 평가해주는 서비스.</p>
</blockquote>
<h2 id="aws-cloudtrail">AWS CloudTrail</h2>
<p>   AWS CloudTrail은 <strong>AWS 계정의 운영 및 위험 감사, 거버넌스 및 규정 준수를 활성화하는 데 도움이 되는 AWS 서비스</strong>입니다. 사용자, 역할 또는 AWS 서비스가 수행하는 작업은 CloudTrail에 <strong>이벤트로 기록</strong>됩니다. 이벤트에는 AWS Management Console, AWS Command Line Interface 및 AWS SDK, API에서 수행되는 작업들이 포함됩니다.</p>
<p>   CloudTrail은 AWS 계정에서 생성 시 활성화되어 있으며, 수동 설정이 필요하지 않습니다. 활동이 AWS 계정에서 이루어지면 해당 활동이 CloudTrail 이벤트에 기록됩니다.</p>
<ul>
<li>이전에 구성된 리소스를 추적하여 변경 사항을 추적할 수 있다.</li>
<li>기본 옵션으로 로그 파일은 S3에 SSE-S3 암호화로 암호화되어 저장됩니다. 추가적으로 SSE-KMS를 사용할지를 결정할 수 있습니다.</li>
</ul>
<h2 id="aws-cloudwatch">AWS CloudWatch</h2>
<p>Amazon CloudWatch는 Amazon Web Services(AWS)에서 제공하는 모니터링 및 관찰성 서비스입니다. 이 서비스는 AWS 리소스와 AWS에서 실행되는 애플리케이션을 실시간으로 모니터링할 수 있도록 설계되었습니다. CloudWatch를 사용하면 컴퓨팅, 데이터베이스, 메시징 큐 등 다양한 AWS 리소스에서 발생하는 메트릭을 수집, 추적 및 알람 설정할 수 있습니다. 또한, 로그 파일을 수집 및 분석하고, 특정 이벤트에 대한 자동화된 작업을 실행할 수 있습니다.</p>
<blockquote>
<p>주요 기능</p>
</blockquote>
<ul>
<li>메트릭 수집 및 모니터링: CPU 사용률, 네트워크 트래픽, 디스크 I/O 작업 등의 시스템 수준 메트릭을 수집하고 모니터링할 수 있습니다.</li>
<li>로그 파일 모니터링: 애플리케이션 로그, 시스템 로그 등을 CloudWatch 로그로 전송하고 실시간으로 데이터를 분석할 수 있습니다.</li>
<li>알람: 메트릭이 사전에 정의된 임계값을 초과하거나 특정 조건을 충족하는 경우 SMS, 이메일, Lambda 함수 등을 통해 알림을 받을 수 있습니다.</li>
<li>이벤트: AWS 리소스의 상태 변경과 같은 이벤트에 대응하여 자동화된 작업을 실행할 수 있습니다.</li>
</ul>
<h2 id="aws-cognito">AWS Cognito</h2>
<p>사용자 인증 관리, 소셜 서비스 자격 증명 연동 및 모바일, 웹 애플리케이션 데이터 동기화를 지원하는 서비스입니다.
이 서비스는 주로 두 가지 주요 구성 요소를 제공합니다: <strong>사용자 풀(User Pools)</strong>과 <strong>자격 증명 풀(Identity Pools, 또는 연합된 자격 증명 풀)</strong>. 이 두 구성 요소는 모두 사용자 관리 및 인증을 위해 사용되지만, 각각의 목적과 기능에는 차이가 있습니다.</p>
<h3 id="사용자-풀-user-pools"><strong>사용자 풀 (User Pools)</strong></h3>
<ul>
<li><strong>목적</strong>: 사용자 풀은 애플리케이션 사용자들을 관리하고, 로그인 기능을 직접적으로 제공하는 완전 관리형 사용자 디렉토리입니다.</li>
<li><strong>기능</strong>: 사용자 가입, 로그인, 비밀번호 재설정, 사용자 프로필 관리 등 사용자 관리 기능을 제공합니다. 또한, 이메일 및 SMS를 통한 사용자 검증(예: 이메일 확인, MFA)도 지원합니다.</li>
<li><strong>사용 사례</strong>: 웹 또는 모바일 애플리케이션에 사용자 인증 기능을 추가할 때 주로 사용됩니다.</li>
</ul>
<h3 id="자격-증명-풀-identity-pools"><strong>자격 증명 풀 (Identity Pools)</strong></h3>
<ul>
<li><strong>목적</strong>: 자격 증명 풀은 사용자에게 AWS 리소스에 대한 임시 AWS 자격 증명을 제공하여, 사용자가 AWS 서비스를 직접 호출할 수 있도록 지원합니다.</li>
<li><strong>기능</strong>: 사용자 풀, 소셜 로그인(예: Google, Facebook, Amazon), SAML 기반의 자격 증명 공급자 등 다양한 출처의 인증 정보를 기반으로 AWS 자격 증명을 발급합니다. 발급된 자격 증명을 사용하여 사용자는 설정된 권한 정책에 따라 AWS 리소스에 접근할 수 있습니다.</li>
<li><strong>사용 사례</strong>: 사용자가 AWS 서비스(예: Amazon S3 버킷에 파일 업로드, DynamoDB 테이블 읽기 등)에 직접 접근할 필요가 있는 애플리케이션에 사용됩니다.</li>
</ul>
<blockquote>
<p>결론: </p>
</blockquote>
<ul>
<li><strong>주요 기능</strong>: 사용자 풀은 애플리케이션 내의 사용자 인증 및 관리에 초점을 맞추고 있으며, 자격 증명 풀은 인증된 사용자에게 AWS 리소스에 대한 접근 권한을 제공하는 것에 중점을 둡니다.</li>
<li><strong>인증 방법</strong>: 사용자 풀은 직접적인 사용자 인증을 처리하고, 자격 증명 풀은 다양한 인증 출처로부터 인증 받은 사용자에게 AWS 자격 증명을 부여합니다.</li>
<li><strong>사용 사례</strong>: 사용자 풀은 사용자 가입 및 로그인 프로세스를 관리하는 데 사용되고, 자격 증명 풀은 사용자가 AWS 리소스에 접근할 수 있도록 하는 데 사용됩니다.</li>
</ul>
<h2 id="aws-key-management-servicekms-aws-secret-manager-aws-certificate-manageracm">AWS Key Management Service(KMS), AWS Secret Manager, AWS Certificate Manager(ACM)</h2>
<p>AWS에서 제공하는 이 세 가지 서비스는 모두 보안과 관련된 기능을 제공하지만, 사용 목적과 기능면에서 서로 다릅니다. 여기 각각에 대한 간략한 설명과 차이점을 정리하겠습니다.</p>
<h4 id="aws-key-management-service-aws-kms"><strong>AWS Key Management Service (AWS KMS)</strong></h4>
<ul>
<li><strong>기능</strong>: AWS KMS는 <strong>암호화 키 관리를 중앙에서 수행</strong>할 수 있는 서비스입니다. 이 서비스를 사용하여 데이터 키를 생성, 관리 및 회전할 수 있으며, 데이터를 암호화하고 해독하는 데 사용됩니다.</li>
<li><strong>사용 사례</strong>: 데이터베이스 파일, 객체 스토리지에 저장된 파일, 미사용 데이터(저장 시 암호화) 및 전송 중인 데이터를 암호화하는 데 사용됩니다.</li>
<li><strong>주요 기능</strong>: 암호화 키의 생성, 관리, 회전, 사용 정책 설정 및 키 사용 로깅.</li>
</ul>
<h4 id="aws-secrets-manager"><strong>AWS Secrets Manager</strong></h4>
<ul>
<li><strong>기능</strong>: AWS Secrets Manager는 애플리케이션에서 사용하는 (예: 데이터베이스 비밀번호, 자격증명, API 키 등)을 안전하게 저장하고 관리하는 데 사용되는 서비스입니다.</li>
<li><strong>사용 사례</strong>: 데이터베이스 비밀번호, OAuth 토큰, API 키 등의 애플리케이션 비밀을 안전하게 관리하고 자동으로 회전시키기 위해 사용됩니다.</li>
<li><strong>주요 기능</strong>: 비밀의 안전한 저장, 자동 회전, 액세스 관리 및 비밀의 사용 로깅.</li>
</ul>
<h4 id="aws-certificate-manager-acm"><strong>AWS Certificate Manager (ACM)</strong></h4>
<ul>
<li><p><strong>기능</strong>: ACM은 SSL/TLS 인증서를 관리하는 서비스입니다. 이를 통해 사용자는 HTTPS를 사용하는 웹 사이트 및 애플리케이션을 위한 인증서를 쉽게 프로비저닝, 관리 및 배포할 수 있습니다.</p>
</li>
<li><p><strong>사용 사례</strong>: 웹 사이트 및 애플리케이션에 SSL/TLS 보안을 추가하고 클라이언트와 서버 간의 안전한 데이터 전송을 보장하기 위해 사용됩니다.</p>
</li>
<li><p><strong>주요 기능</strong>: SSL/TLS 인증서의 프로비저닝, 관리, 자동 갱신.</p>
<blockquote>
<p><strong>차이점 요약</strong>:</p>
</blockquote>
<ul>
<li><strong>KMS</strong>: 암호화 키 관리 및 데이터 암호화/해독에 초점.</li>
<li><strong>Secrets Manager</strong>: 애플리케이션 비밀(비밀번호, 키) 관리 및 자동 회전에 초점.</li>
<li><strong>ACM</strong>: SSL/TLS 인증서의 생명 주기 관리(프로비저닝, 갱신)에 초점.</li>
</ul>
</li>
</ul>
<h2 id="aws-guardduty-aws-inspector-차이">AWS GuardDuty, AWS Inspector 차이</h2>
<h4 id="aws-guardduty"><strong>AWS GuardDuty</strong></h4>
<ul>
<li><p><strong>위협 탐지 중심</strong>: GuardDuty는 주로 네트워크 트래픽과 계정 활동에 대한 지속적인 모니터링을 통해 비정상적인 행위, 비정상적인 로그인 시도, 비정상적인 API 호출 패턴, 악의적인 IP 주소로부터의 트래픽 등을 식별합니다. 이는 외부 또는 내부로부터 오는 위협과 공격 시도를 실시간으로 탐지하는 데 초점을 맞춥니다.</p>
</li>
<li><p><strong>패시브 보안</strong>: GuardDuty는 설치나 에이전트 없이 AWS 환경에서 발생하는 이벤트를 분석합니다. 사용자의 개입 없이도 자동으로 위협 탐지를 수행하고, 해당 사항을 알립니다.</p>
<h4 id="aws-inspector"><strong>AWS Inspector</strong></h4>
</li>
<li><p><strong>취약점 관리 중심</strong>: Inspector는 AWS 리소스의 구성과 관련된 취약점을 평가하고, 해당 취약점을 해결하기 위한 권장 사항을 제공합니다. 예를 들어, EC2 인스턴스의 운영 체제에 적용되지 않은 패치, 잘못 구성된 네트워크 액세스 규칙, 보안 그룹 설정의 문제 등을 분석합니다.</p>
</li>
<li><p><strong>액티브 보안 평가</strong>: Inspector를 사용하기 위해서는 평가 대상의 EC2 인스턴스에 에이전트를 설치하고, 평가를 실행할 규칙 세트를 선택해야 합니다. 사용자는 평가를 시작하고, 결과를 검토하여 취약점을 해결하는 데 필요한 조치를 취해야 합니다.</p>
</li>
</ul>
<h4 id="핵심-차이">핵심 차이:</h4>
<ul>
<li><strong>목적</strong>: GuardDuty는 위협 탐지와 실시간 보안 모니터링에, Inspector는 취약점 관리와 시스템의 보안 상태 평가에 중점을 둡니다.</li>
<li><strong>작동 방식</strong>: GuardDuty는 사용자의 개입 없이 AWS 환경에서 자동으로 이루어지는 패시브 보안 분석을 제공하는 반면, Inspector는 사용자가 직접 평가를 구성하고 실행하여 액티브한 보안 평가를 수행합니다.</li>
<li><strong>대상</strong>: GuardDuty는 네트워크 트래픽과 계정 활동에 대한 분석을 통해 위협을 탐지하는 반면, Inspector는 서버의 취약점과 구성 문제를 중점적으로 평가합니다.</li>
</ul>
<blockquote>
<p>결론:
  GuardDuty는 &quot;외부와 내부로부터 오는 위협을 실시간으로 탐지&quot;하는 데 초점을 맞추고, Inspector는 &quot;시스템의 취약점을 평가하고 개선 권장사항을 제공&quot;하는 데 중점을 둡니다. 이 두 서비스는 함께 사용될 때 AWS 환경의 보안을 종합적으로 강화할 수 있습니다.</p>
</blockquote>
<h2 id="aws-security-hub">AWS Security Hub</h2>
<p>   AWS Security Hub는 GuardDuty , Inspector, Macie 등을 포함한 다양한 서비스에서 보안 <strong>결과를 집계하고 우선순위를 지정하는 중앙 보안 관리 서비스</strong>다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GIT 기본개념]]></title>
            <link>https://velog.io/@sungmin-choi/GIT-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@sungmin-choi/GIT-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90</guid>
            <pubDate>Sun, 29 May 2022 04:29:48 GMT</pubDate>
            <description><![CDATA[<h3 id="repository">Repository:</h3>
<ul>
<li>Repository 는 Git이 파일들과 폴더들을 주시하는곳 입니다.</li>
<li>Git이 컴퓨터의 있는 directory 를 monitor 하고 있고 그것을 Github (Cloud)에 업로드하면 repository 에 저장됩니다.</li>
<li>그러므로 사실상 Github - cloud 에 저장되 있는 repository 하고 내 컴퓨터에서 Git이 주시하고 있는 repository 두 군데가 있는 셈입니다.</li>
<li>Git이 우리 컴퓨터에 있는 파일들을 주시하는 방법은 directory 로 지정이 되었을때 .gitattributes 하고 .git 이라는 hidden file 들이 생성이 되는데 이 파일들의 기능을 통해 Git은 directory 에 있는 모든 파일 변화들을 track 할수 있습니다.</li>
<li>정리하자면 Git은 파일들의 변화를 track 하기 위해서 존재합니다. 나중에 큰 코드나 앱 파일들이 업데이트 되었을때 앱의기능이 작동안하고 에러가 떳을때 어떠한 변화가 에러를 유발시켰는지 찾고 변화를 취소(retract) 할수 있기 때문에 많은 회사들이 Git 사용하고 있습니다.</li>
</ul>
<h3 id="commit">Commit</h3>
<ul>
<li>Commit 은 변화의시점을 정하기 위해 사용됩니다.</li>
<li>처음 commit 을 initial commit 이라고 부르기도 하는데 만약에 GitHub Desktop 을 사용할 경우 commit을 할 경우 Title과 Comment를 쓰는란과 Commit 버튼이 있기 때문에 쉽게 저장 할수 있습니다. 되도록이면 바뀐내용을 간추려서 Title과 Comment에 적는 습관을 들이는게 좋습니다.</li>
<li>회사마다 다르지만 보통 10개 변화 또는 20개의 변화 마다 commit 을 해서 변화의 시점들을 저장합니다. 그래야 변화 이후에 에러가 날경우 변화 이전의 시점으로 되돌릴수 있습니다.</li>
</ul>
<h3 id="git-workflowgit-area">Git workflow(Git Area)</h3>
<p>Git workflow(Git Area)는 기본적으로 3단계로 나눠져 있다.</p>
<ul>
<li><p>Working Directory(Unstage Area)</p>
<p>  우리가 현재 작업하고 있는 폴더로 생성, 수정, 삭제한 파일들이 있는 디렉토리</p>
</li>
<li><p>Staging Area</p>
<p>  Index라고도 부르며 , 변경사항이 있는 파일들을 선택해 커밋할 수 있도록 지정하는 곳</p>
<p>  (버전을 만들기 위해 준비 중인 파일들의 스냅샷 데이터가 저장된 곳)</p>
</li>
<li><p>Git Directory(Local Repository)</p>
<p>  파일들이 커밋된 곳으로, 파일들의 변경사항에 대한 스냅샷을 가지고 있는 곳</p>
<p>  (Staging Area를 거쳐 만들어진 버전들이 저장된 곳)</p>
</li>
</ul>
<h2 id="명령어-모음">명령어 모음</h2>
<ol>
<li><p><code>git init</code> : 저장소 만들기</p>
</li>
<li><p><code>git status</code> : 현재 상태 확인</p>
</li>
<li><p><code>git add [-A] [&lt;pathspec&gt;…]</code> 현재 상태 추적</p>
<p> 파일의 변경사항을 인덱스(staging area)에 추가합니다. Git은 커밋하기전, 인덱스에 먼저 커밋할 파일을 추가합니다.</p>
</li>
<li><p><code>git commit [-m &lt;msg&gt;]</code> : 현재 상태 저장 </p>
<p> 인덱스에 추가된 변경 사항을 이력에 추가.</p>
<p> 깃 커밋 수정하고싶을땐 <code>git commit --amend</code> 사용하면된다.</p>
</li>
<li><p><code>git log</code> : 이력 확인</p>
<p> 다양한 오셥을 조합하여 원하는 형태의 로그를 풀력할 수 있는 강력한 기능. </p>
</li>
<li><p><code>git reset[&lt;commit&gt;] [--soft | --mixed [-N] | --hard | --merge | --keep]</code> : 이전 상태로(이력 제거)</p>
<p> <commit>: 커밋기록 아이디 예: 27a00b7</p>
<p> 특정 커밋까지 이력을 초기화합니다. 바로 전, 또는 n번 전까지 작업했던 내용을 취소할 수 있습니다. 열심히 작업했는데, 전혀 엉뚱한 걸 했거나 작업한 내용이 필요 없어질 때 사용합니다. ⚠️ 이력이 지워지기 때문에 주의   </p>
<p> 커밋 취소 앞에 한개할 경우: <code>git reset HEAD~ 1</code> </p>
</li>
<li><p><code>git reflog</code> </p>
<p> git의 모든 브랜치에서 있었던 지금까지의 모든 기록을 볼 수 있다 각각 HEAD@{index} 형태로 index를 가지고 있으니, 잘못되기 전에 해당하는 index를 찾고 <code>git reset HEAD@{index}</code> 사용하여 돌아가기 </p>
<p> 이 기능은 실수로 지운 파일을 되돌리거나, 뭔가 잘못 수정한 걸 되돌리거나, 실수로 머지한 걸 되돌리거나, 다 됐고 그냥 잘 작동했던 때로 돌아가고 싶을 때 사용하면 된다. 실제로 <code>reflog</code> 를 많이 사용한다고 들었다</p>
</li>
<li><p><code>git revert &lt;commit&gt;…</code> : 이전 상태로(이력 유지)</p>
<p> 특정 커밋을 취소하는 새로운 커밋을 만듭니다. 여기선 3번 커밋을 취소하는 새로운 커밋을 생성하여 마치 2번 커밋 상태로 돌아간 것 같지만 기존 이력을 유지하는 모습을 확인합니다.</p>
<p> 일반적으로 특정 버전을 배포했는데 문제가 생기면 문제가 생긴 커밋을 <code>revert</code>합니다. (빠른 조치/롤백) 다시 원복한 상태로 작업을 이어서 하고 해당 문제를 수정하면 다시 커밋하는 방식을 사용합니다.</p>
</li>
<li><p><code>git branch 새로운 브랜치 이름</code> 새로운 브랜치 생성</p>
<ul>
<li><code>git branch</code> : 브랜치 목록 확인</li>
<li><code>git branch -d 삭제할 브랜치</code></li>
</ul>
</li>
<li><p><code>git switch -c</code> : 브랜치 생성 및 이동</p>
<p>‘-c’ 옵션은 브랜치 생성과 동시에 이동을 한번에 수행합니다. </p>
</li>
<li><p><code>git merge 브랜치 이름</code> : 브랜치 병합 </p>
<p>예) dev브랜치를 main 브랜치로 병합하고 싶으면  main 브랜치 상태에서 <code>git merge dev</code> 해주자.</p>
</li>
<li><p><code>git rebase &lt;메인브랜치&gt; &lt;이동할 브랜치&gt;</code> </p>
<p>merge와 rebase의 차이점:</p>
<p>말 그대로 branch base를 이동시킨다는 뜻으로, 머지처럼 브랜치 통합을 목적으로 하지만, 특정 시점으로 브랜치가 가리키는 곳을 변경하는 기능을 합니다.</p>
<p>그림에서 보이는 것과 같이 feature/login 브랜치에서 git rebase main feature/login 명령어를 입력하면 main의 가장 최신 커밋으로 브랜치가 가리키는 곳이 변경됩니다. (main의 다른 커밋에서 충돌이 없을 경우)
<img src="https://velog.velcdn.com/images/sungmin-choi/post/c8ffb701-dc53-4cc7-a7f8-3d9813951374/image.png" alt=""></p>
</li>
<li><p><code>conflict</code> : 충돌 해결 </p>
<p>대부분 협업을 할때 서로 다른 작업을 하므로 보통 문제없이 자동으로 머지됩니다. <strong>하지만,</strong> 같은 파일을 부득이 수정하는 경우가 생기고 필연적으로 충돌이 발생하는데, 강제로 상황을 만들고 충돌을 해결하는 방법을 알아보겠습니다.</p>
<p>충돌은 정말 마주치고 싶지 않은 상황입니다. 하지만, 상황이 발생했으면 해결을 해야겠죠.</p>
<p>충돌을 해결하고 커밋을 하거나, 머지 작업을 취소 <code>git merge --abort</code> 할 수 있습니다.</p>
</li>
<li><p><code>git remote add &lt;name&gt; &lt;url&gt;</code> : </p>
<p>Git은 여러 개의 원격 저장소를 등록할 수 있고 기본 저장소의 이름이 <code>origin</code> 입니다. GitHub을 메인 원격 저장소(origin)로 사용하고 Google Cloud에 추가로 원격 저장소 설정을 한다면 <code>google</code>이라는 이름을 사용할 수 있습니다.</p>
<pre><code class="language-bash">git remote add origin &lt;url&gt;

git remote add google &lt;google reository url&gt;</code></pre>
</li>
<li><p><code>git push [-u | --set-upstream] [&lt;repository&gt; [&lt;refspec&gt;…]]</code> :원격 저장소 저장</p>
<p>로컬 저장소를 GitHub에 푸시합니다. 로컬 저장소의 커밋 목록이 그대로 복제될 예정입니다.</p>
</li>
<li><p><code>git clone &lt;repository&gt; [&lt;directory&gt;]</code> : 원격 저장소 복제</p>
<p>원격 저장소를 로컬로 가져오는 명령어</p>
</li>
<li><p><code>git pull [&lt;repository&gt; [&lt;refspec&gt;…]]</code> : 원격 저장소 내용 가져오기</p>
<p>원격 저장소에 변경된 내용을 로컬 저장소로 가져옵니다. Git은 자동으로 원격 저장소와 로컬 저장소를 동기화하지 않습니다. 명시적으로 명령어를 입력해야 합니다.</p>
<blockquote>
<h3 id="개인이-정한-커밋메세지-규칙">개인이 정한 커밋메세지 규칙</h3>
</blockquote>
</li>
</ol>
<p><strong>커밋 유형 지정</strong>
    - FEAT : 새로운 기능의 추가
    - FIX: 버그 수정
    - DOCS: 문서 수정
    - STYLE: 스타일 관련 기능(코드 포맷팅, 세미콜론 누락, 코드 자체의 변경이 없는 경우)
    - REFACTOR: 코드 리펙토링
    - TEST: 테스트 코트, 리펙토링 테스트 코드 추가
    - CHORE: 빌드 업무 수정, 패키지 매니저 수정(ex .gitignore 수정 같은 경우)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 개념정리]]></title>
            <link>https://velog.io/@sungmin-choi/React-%EA%B0%9C%EB%85%90%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@sungmin-choi/React-%EA%B0%9C%EB%85%90%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 07 May 2022 08:07:34 GMT</pubDate>
            <description><![CDATA[<h3 id="react란">React란?</h3>
<p>UI를 구축 하기위한 자바스크립트 프론트엔드 라이브러리입니다. 주로SPA를 구현할때 사용합니다.</p>
<h3 id="react-장점은">React 장점은?</h3>
<ul>
<li>VirtualDOM을 사용해서 실제 DOM에 직접접근해서 제어하는 것을 최소화해서 어플리케이션 최적화에 도움이됩니다.</li>
<li>SPA기반 으로 구현되기때문에 사용자경험이 많은 어플리케이션이면 효과빠른 화면전환을 경험할 수 있다.</li>
<li>React는 현재 엄청난 커뮤니티 및 시장에서 제일많이쓰는 라이브러리중 하나이다, 즉 많은 서드파티 라이브러리들이 재공이됩니다. 그리고 에러문제가 생겨도 해당 에러에대한 정보도 굉장히 많기때문에 해결하기도 쉽다.</li>
<li>component 기반으로 구축하기때문에 재사용성, 유지보수, 에러핸들링에 유용하다.</li>
<li>많은 외부 라이브러리랑 호환성이 뛰어나다.</li>
</ul>
<h3 id="virtualdom이란">VirtualDOM이란?</h3>
<p>실제 DOM에 접근해서 제어하는것이 아닌 DOM형태에 객체를 메모리에 할당하여 애플리케이션에 상태가 바뀔때 그전에 저장한 VirtualDom과 현재 바뀐 VirtualDOM과 비교해서 변경된값만 종합해서 바뀐값만 다시 실제DOM에 접근해서 변경해준다.이 과정을 재조정(Reconciliation) 이라고 한다.
virtual DOM을 갱신하는 방법은</p>
<blockquote>
<h4 id="virtual-dom을-갱신하는-방법은">virtual DOM을 갱신하는 방법은</h4>
</blockquote>
<ul>
<li>useState를 호출하여 state를 바꿀때</li>
<li>redux의 경우 store 안에 값이 바뀌면 최상위에 컴포넌트의 render()함수를 호출해서 virtualDOM 을 갱신한다.</li>
<li>props가 바뀔때</li>
</ul>
<h3 id="props-drilling이란">Props Drilling이란?</h3>
<p>Props Drilling라는 것은 부모컴포넌트에 있는 state값을 자식컴포넌트에 props로 데이터를 전달하는 것을(내려꽂기)를 말한다. 어필리케이션의 컴포넌트간에 깊이가 깊어질수록 props Drilling 단점이 확연하게 보인다.
<img src="https://i0.wp.com/blogs.perficient.com/files/react-5.png?w=718&ssl=1" alt="image">
위 사진을 보면 최하위컴포넌트가 최상컴포넌트에 state를 받아오고싶으면 중간에 속해진 컴포넌트를 통해서 계속계속 props전달을 해야합니다. 정말 비효율적이겠죠? 애플리케이션 규모가 커지면 커질수록 단점은 드러나고. 에러핸들링 데이터 추적도 굉장히 힘들어집니다 중간 컴포넌트는 필요없는 props를 위해서 굳이 코드작성도 해줘야하고 여러므로 안좋습니다. 그래서 사용하게되는것이 상태관리 라이브러리입니다 대표적으로 Redux, ContextAPI, Mobx가 있습니다.</p>
<h3 id="state와-props의-차이는">state와 props의 차이는?</h3>
<p>state는 현재 컴포넌트의 생명주기 동안에 변경될 수 있는 정보를 담고 있는 상태이고, props는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 데이터입니다.</p>
<h3 id="제어컴포넌트비제어컴포넌트">제어컴포넌트,비제어컴포넌트</h3>
<p>제어 컴포넌트의 경우 리액트 state에 의해서 값이 관리 및 변경이 되고, 비제어 컴포넌트의 경우 ref를 통해 DOM 자체에서 form 데이터가 다뤄집니다. 가장 큰 차이점은 동기화인데, 제어 컴포넌트의 경우 사용자가 입력할 때마다 input의 state가 동기화되지만 state가 변경될 때마다 리렌더링이 발생하여 불필요한 자원의 낭비로 이어질 수 있습니다. 반면 비제어 컴포넌트의 경우 입력을 하고 버튼을 누르는 최종적인 상황에서만 input의 value에 접근을 하므로 리렌더링이 계속해서 발생하지는 않지만 입력의 최신 값에 접근하기 힘든 특성이 존재합니다.</p>
<h3 id="jsx란">JSX란?</h3>
<p>자바스크립트에서 HTML문법을 사용할 수 있게 해주는 자바스크립트 확장문법이다. HTML파일 JS파일 따로 나눠서 작성안해도되서 편하고 가독성에 좋다.</p>
<h3 id="함수형-컴포넌트의-장점은">함수형 컴포넌트의 장점은?</h3>
<ul>
<li>클래스형 컴포넌트보다 선언이 간편</li>
<li>클래스형 컴포넌트보다 메모리 자원을 절약</li>
<li>this 키워드 안사용해도 된다</li>
<li>많은 라이프사이클 메소드 사용 생략</li>
</ul>
<h3 id="리액트-라이프사이클">리액트 라이프사이클?</h3>
<p>react LifeCiycle 는 리액트 컴포넌트가 DOM에 생성,업데이트,삭제될때 호출되는 API를 말한다.
<img src="https://i.imgur.com/cNfpEph.png" alt="image"></p>
<ul>
<li><strong>constructor</strong> : 컴포넌트의 생성자 메서드. 컴포넌트 생성 시 가장 먼저 실행되는 메서드. 초기 state를 설정</li>
<li><strong>getDerivedStateFromProps</strong> : props로 받아온 것을 state에 넣어주고 싶을 때 사용</li>
<li><strong>render</strong> : 컴포넌트를 렌더링 하는 메서드</li>
<li><strong>componentDidMount</strong> : 컴포넌트의 첫 번째 렌더링을 마치고 호출되는 메서드. 주로 여기서 비동기 요청 작업 처리</li>
<li><strong>shouldComponentUpdate</strong> : 컴포넌트를 리렌더링 할지 말지를 결정하는 메서드</li>
<li><strong>getSnapshotBeforeUpdate</strong> : Virtual DOM이 실제 DOM에 반영되기 직전에 실행. 이 메서드에서는 이전과 현재의 props와 state에 접근이 가능하고 return으로 넘겨진 값은 componentDidUpdate의 3번째 인자로 전달됨</li>
<li><strong>componentDidUpdate</strong> : 리렌더링을 마치고 화면에 변화가 모두 반영되고 난 뒤 호출되는 메서드</li>
<li><strong>componentWillUnmount</strong> : 컴포넌트가 화면에서 사라지기 직전에 호출되는 메서드</li>
</ul>
<h3 id="react-hooks란">React Hooks란?</h3>
<p>React Hook은 함수형 컴포넌트에서도 클래스형 컴포넌트의 기능을 사용할 수 있게 하는 기능입니다. Hook을 통해서 함수형 컴포넌트에서도 컴포넌트의 상태 값을 관리할 수 있고 생명주기 메서드 또한 사용이 가능합니다.</p>
<h3 id="usecallback-usememo-란">useCallback, useMemo 란?</h3>
<p>useMemo는 메모이제이션 된 값을 반환한다. 컴포넌트는 상태값이 변경될 때마다 재 렌더링이 됩니다.
값이 변경이 되지 않는 상태값도 다른 상태값이 바뀌었다는 이유로 굳이, 값을 재 설정할 필요가없기때문에 그럴 경우데 useMemo를 써서 최적화를 효과를볼 수 있다.
useCallback는 메오이제이션 된 콜백을 반환한다. 콜백함수를 메모리에 올려놓고 사용한다는 뜻입니다. 의존배열에 있는 state값이 안바뀌었는데 굳이 다시 함수를 다시 실행시켜서 같은결과를 return 할 필요가 없기때문에 그럴때 사용하면됩니다.
하지만 React 공식문서에서는 아주 큰 계산(useCallback인 경우), 처리량이 크지않은이상(useMemo인 경우) 굳이 안써도 된다고 기재되어있다.</p>
<h3 id="useeffect-uselayouteffect-차이">useEffect, useLayoutEffect 차이</h3>
<p>useEffect는 react hooks중 일종으로 LifeCiycle 메소드중 componentDidMount, componentDidUpdate, componentWillUnmount 와 비슷한 기능을 제공합니다. 
useEffect와 useLayoutEffect의 차이를 알기전에 먼저 render와 paint에대해서 알고 넘어가는것이 좋다.</p>
<ul>
<li><strong>render</strong> : DOM tree를 만들기위해서 HTML파일을 파싱하는 style 속성을 계산하는과정.</li>
<li><strong>Paint</strong> : 실제 화면에 그려주기위해 Layout을 표시하고 업데이트하는 과정.</li>
</ul>
<h4 id="useeffect"><strong>useEffect</strong></h4>
<p>useEffect 는 컴포넌트들이 render 와 paint 된 후 실행됩니다. <strong>비동기적(asynchronous)</strong> 으로 실행됩니다. paint 된 후 실행되기 때문에, useEffect 내부에 dom 에 영향을 주는 코드가 있을 경우 사용자 입장에서는 <strong>화면의 깜빡임을 보게됩니다</strong>.</p>
<h4 id="uselayouteffect"><strong>useLayoutEffect</strong></h4>
<p>useLayoutEffect 는 컴포넌트들이 render 된 후 실행되며, 그 이후에 paint 가 됩니다. 이 작업은 <strong>동기적(synchronous)</strong> 으로 실행됩니다. paint 가 되기전에 실행되기 때문에 dom 을 조작하는 코드가 존재하더라도 사용자는 <strong>깜빡임을 경험하지 않습니다</strong>.</p>
<blockquote>
<h4 id="결론"><strong>결론</strong></h4>
<p>useLayoutEffect 는 동기적으로 실행되고 내부의 코드가 모두 실행된 후 painting 작업을 거칩니다. 따라서 로직이 복잡할 경우 사용자가 레이아웃을 보는데까지 시간이 오래걸린다는 단점이 있어, 기본적으로는 항상 useEffect 만을 사용하는 것을 권장드립니다. 구체적인 예시로는</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 접근성(Accessibility, a11y)]]></title>
            <link>https://velog.io/@sungmin-choi/%EC%9B%B9-%EC%A0%91%EA%B7%BC%EC%84%B1Accessibility-a11y</link>
            <guid>https://velog.io/@sungmin-choi/%EC%9B%B9-%EC%A0%91%EA%B7%BC%EC%84%B1Accessibility-a11y</guid>
            <pubDate>Sun, 24 Apr 2022 09:32:46 GMT</pubDate>
            <description><![CDATA[<p>웹 접근성은 모든 신체적 한계, 환경적 한계를 고려해 개발하는 것을 의미합니다. 웹 접근성을 따르는 개발은 장애가 있거나 노령으로 인한 신체 변화, 여러 기기 환경을 사용하는 모든 사람이 웹 사이트와 도구등을 사용할 수 있도록 개발 라는하을 의미합니다. </p>
<h2 id="웹-접근성-지침-준수-사항">웹 접근성 지침 준수 사항</h2>
<p>WCAG(Web Content Accessibility) 기반으로 몇 가지 가이드라인과 적용방법을 토대로 설명 할것이다.</p>
<ul>
<li><p><strong>속어 약어 사용을 지양하라</strong></p>
<p>  속어나 약어 같은경우 장애를 가진 사람이든 가지지 않은 사람 모두가 정보를 이해할 가능성이 매우 낮기 때문에 가급적으로는 표준용어로  모든 사용자분 들이 이해할 수 있게끔 쓰는것을 권고한다.</p>
</li>
<li><p><strong>콘텐츠의 제목과 단락을 명확하게 구분하자</strong></p>
<p>  스크린 리더는 컴퓨터의 화면을 읽어 주는 프로그램입니다. 시각적으로 정보를 획득하기 어려운 사람들을 위해서 화면에 나타나는 정보를 기계가 음성으로 읽어 줍니다. 콘텐츠 내 에 제목과 단락을 제대로 구분을 해줘야 기계가 글의 내용을 파악할 때 도움을 주기 때문에 .HTML 작성할 때 제목 요소와 단락을 내용의 의미에 맞게 나누는 것이 중요합니다.  시맨틱 하게 HTML 작성을 하면 기계가 각 태그에 의미에 맞게 요소의 내용에 맞게 읽는 방식으로 조절을 해 줍니다.</p>
</li>
<li><p><strong>키보드 동작을 제공하자</strong></p>
  <br/>
  tab을 사용해서 다음 input으로 이동해보자: <input type="text" placeholder="tab me!"/>
  <input type="text" />
  <br/>

<p>  <code>&lt;button&gt;</code> , <code>&lt;input&gt;</code>, <code>&lt;select&gt;</code> 요소를 사용하지않고 <code>&lt;div&gt;</code> 와 CSS를 이용해 지슷하게 구현을 해 사용할 때도 있습니다. 이럴땐 엔터 키나 탭 키를 누를 때 해당 요소로 이동시키는 동작과 같은 상호작용들을 누릴 수 없습니다.  스크린 리더가 그냥 div 만 설정하면 이 요소를 선택해야 하는 요소인지, 이벤트를 발생시키는 요소인지 파악하지 못한다.</p>
<p>  그래서 div 요소를 사용해야한다면 추가적인 코드 작성으로 사용목적을 정확하게 명시를 해 줘야합니다.</p>
<p>  role: 해당 요소의 목적</p>
<p>  tab-index: 해당 요소를 탭 키로 도달하게 하는 속성.</p>
<p>  키보드 이벤트 리스너 추가하기</p>
</li>
<li><p><strong>Foucus하는 지점 명확하게</strong></p>
<p>  웹 사이트는 키보드만으로 모든 기능이 동작해야 합니다. </p>
  <br/>
  foucus 하시면 윤곽선이 나타난다: <input type="text" placeholder="foucos me!" />
  <br/>
  항목에 Focus가 된다면 시력이 있는 사용자를 위해 윤곽선이 나타나야한다.(윤곽선은 기본으로 나타난다 하지만 css 설정으로 없앨 수 있다 그럴경우 다른방법으로 focus 되어있는지 나타내야합니다)
</li>
<li><p><strong>멀티미디어 요소에 접근성을 부여하자</strong></p>
<p>  이미지나 동영상,오디오는 모든 스크린 리더가 접근할 수 없다.  시각장애 혹은 청각장애가 있으신분은 접근하기가 힘들다 그래서 이런분들에게 의미를 전달하기위해서 존재하는 속성이있습니다.</p>
<pre><code class="language-jsx">  // bad
  &lt;img src=”coffee.png” /&gt;
  // good
  &lt;img src=”coffee.png” alt=&quot;컵에 담긴 따듯한 아메리카노&quot; title=&quot;아메리카노&quot;/&gt;
</code></pre>
<p>  이렇게 좋은 예제처럼 alt ,title 속성추가하여 작성하면 스크린리더가 더 명확하고 자세하게 이미지의 의미를 전달할 수 있다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dijkstra(다익스트라)]]></title>
            <link>https://velog.io/@sungmin-choi/Dijkstra%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC</link>
            <guid>https://velog.io/@sungmin-choi/Dijkstra%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC</guid>
            <pubDate>Sun, 24 Apr 2022 07:25:31 GMT</pubDate>
            <description><![CDATA[<p>그래프에서 특정 정점에서 목적지까지 최단 경로를 구하는 알고리즘</p>
<p>대표적인 최단 경로 알고리즘중 하나가 다익스트라 알고리즘이다.</p>
<h3 id="bfsdfs-를-사용하는-경우가중치가-같을경우">BFS,DFS 를 사용하는 경우(가중치가 같을경우)</h3>
<p>그래프의 간선 가중치가 모두 같을 때 적합하다.</p>
<p>예를 들어 2차원배열에서 입력이 주어진 상태로 시작점에서 도착점까지의 최단경로 구할때 어떤 위치에서 다음위치까지 거리가 같기때문에 BFS,DFS 를 사용해서 최단경로를 구하는게 대부분이다.</p>
<h3 id="가중치가-다를땐-어떤방식으로-해야할까요">가중치가 다를땐 어떤방식으로 해야할까요?</h3>
<p>이번에 배워볼 다익스트라 알고리즘으로 가중치가 다를때 구하는게 적합하다. </p>
<h3 id="다익스트라-알고리즘이란">다익스트라 알고리즘이란?</h3>
<ul>
<li>Edsger Wybe Dijkstra가 고안한 최단경로 알고리즘.</li>
<li>우선순위 큐를 이용하려 만들 수 있다.</li>
<li>시간복잡도는 V가 정점의 수, E가 간선의 수일때 시간복잡도는 Elog V 가 된다.</li>
</ul>
<h3 id="다익스트라-알고리즘-순서">다익스트라 알고리즘 순서</h3>
<ol>
<li>먼저 시작점을 제외한 나머지 정점을 다 무한값으로 초기화 해준다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/sungmin-choi/post/629e2983-f406-44ca-be2b-15bd261a671c/image.jpeg" alt=""></p>
<ol start="2">
<li>시작점 기준으로 시작점에서 갈 수 있는 정점을 찾고 값을 재할당 해 준다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/sungmin-choi/post/d6f9a329-296e-4222-a23f-e7743cd08dab/image.jpeg" alt=""></p>
<ol start="3">
<li>여기서 설정된 정점중에 최단거리가 제일 짧은 정점을 선택해 준다. 선택후 해당 정점(E)에서 또 뻗어나간 간선을 통해서 정점 값을 재할당 해 준다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/sungmin-choi/post/81cc67f8-2854-40fc-85b3-1d488d54bea0/image.jpeg" alt=""></p>
<ol start="4">
<li>이제 현재정점(E)을 방문처리한 후 다음으로 최단거리인 정점(B)을 선택한후에 똑같은 방식으로 진행을 한다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/sungmin-choi/post/bca6425a-d41f-4e3c-809a-aebc309f56ac/image.jpeg" alt=""></p>
<p>B정점에서 갈수 있는 정점은 C 바께 없음을 확인하실 수 있습니다. 여기서 기존에 C정점의 값이 5였는데 A→B→C 로 가는값이 4다. 즉 기존에 5보다 짧기때문에 다시 C정점에 값을 재할당 해 준다. </p>
<ol start="5">
<li>계속 이런 절차를 통해서 진행해서 모든 정점이 다 방문처리되면</li>
</ol>
<p><img src="https://velog.velcdn.com/images/sungmin-choi/post/d86e485a-69c9-4db9-bee7-682190c0852e/image.jpeg" alt=""></p>
<p>이런식으로 모드 값이 할당된게 보인다.</p>
<p>다익스트라 알고리즘을 보면 계속해서 가장 값이 낮은 정점을 선택하여 진행이되는 것 을 볼 수 있습니다. 따라서 해당 절차를 구현하기 위해서는 우선순위 큐 통해서 구현을 해야합니다. 이를 효율적으로 구현하기 위해서는 힙을 사용하실 수 있습니다.</p>
<h3 id="다익스트라-정리">다익스트라 정리</h3>
<ol>
<li>시작점을 제외한 모든 정점의 거리를 무한으로 설정한다. 시작점은 0으로 설정한뒤 시작한다.</li>
<li>선택한 정점에서 갈 수 있는 정점의 거리를 정점(해당 정점까지의 최단 거리)값 + 간선(거리)값 으로 갱신한다.</li>
<li>선택한 정점을 방문 처리한다.</li>
<li>이미 방문한 정점과 무한인 정점을 제외하고 가장 최단 거리인 정점을 선택한다.</li>
<li>더 이상 방문할 수 있는 정점이 없을 때 까지3~5를 반복.</li>
<li>바지막에 도착의 값을 확인한다.</li>
</ol>
<h3 id="예제">예제</h3>
<p><a href="https://programmers.co.kr/learn/courses/13213/lessons/91411">프로그래머스 배달문제</a></p>
<pre><code class="language-js">// 최소힙 
class MinHeap {
  constructor() {
    this.heap = [null];
  }
  push(value) {
    this.heap.push(value);
    let currentIndex = this.heap.length - 1;
    let parentIndex = Math.floor(currentIndex / 2);
    while (
      parentIndex !== 0 &amp;&amp;
      this.heap[parentIndex].cost &gt; this.heap[currentIndex].cost
    ) {
      this._swap(parentIndex, currentIndex);
      currentIndex = parentIndex;
      parentIndex = Math.floor(currentIndex / 2);
    }
  }

  pop() {
    if (this.isEmpty()) return;
    if (this.heap.length === 2) return this.heap.pop();
    const returnValue = this.heap[1];
    this.heap[1] = this.heap.pop();

    let currentIndex = 1;
    let leftIndex = 2;
    let rightIndex = 3;

    while (
      (this.heap[leftIndex] &amp;&amp;
        this.heap[currentIndex].cost &gt; this.heap[leftIndex].cost) ||
      (this.heap[rightIndex] &amp;&amp;
        this.heap[currentIndex].cost &gt; this.heap[rightIndex].cost)
    ) {
      if (this.heap[leftIndex] === undefined) {
        this._swap(currentIndex, rightIndex);
      } else if (this.heap[rightIndex] === undefined) {
        this._swap(currentIndex, leftIndex);
      } else if (this.heap[leftIndex].cost &lt; this.heap[rightIndex]) {
        this._swap(currentIndex, leftIndex);
      } else {
        this._swap(currentIndex, rightIndex);
      }
      leftIndex = currentIndex * 2;
      rightIndex = currentIndex * 2 + 1;
    }
    return returnValue;
  }

  isEmpty() {
    return this.heap.length === 1;
  }

  _swap(a, b) {
    [this.heap[a], this.heap[b]] = [this.heap[b], this.heap[a]];
  }
}

// 다익스트라 알고리즘
function dijkstra(road, N) {
  const heap = new MinHeap();
  heap.push({ node: 1, cost: 0 });

  const dist = [...Array(N + 1)].map(() =&gt; Infinity);
  dist[1] = 0;

  while (!heap.isEmpty()) {
    const { node: current, cost: currentCost } = heap.pop();

    for (const [src, dest, cost] of road) {
      const nextCost = cost + currentCost;

      //양방향 고려하여 작성
      if (src === current &amp;&amp; nextCost &lt; dist[dest]) {
        // src가 현재 선택된 정점이면서 목적지까지 더 저렴할 경우
        dist[dest] = nextCost; // 거리를 갱신한다.
        heap.push({ node: dest, cost: nextCost });
      } else if (dest === current &amp;&amp; nextCost &lt; dist[src]) {
        dist[src] = nextCost;
        heap.push({ node: src, cost: nextCost });
      }
    }

    return dist;
  }
}

function solution(N, road, K) {
  const dist = dijkstra(road, N);
  return dist.filter((x) =&gt; x &lt;= K).length;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Heap(힙)]]></title>
            <link>https://velog.io/@sungmin-choi/Heap%ED%9E%99</link>
            <guid>https://velog.io/@sungmin-choi/Heap%ED%9E%99</guid>
            <pubDate>Sun, 17 Apr 2022 10:43:56 GMT</pubDate>
            <description><![CDATA[<h2 id="힙이란">힙이란?</h2>
<p>이진 트리 형태를 가지며 우선순위가 높은 요소가 먼저 나가기 위해 요소가 삽입, 삭제 될 때 바로 정렬되는 특징이 있다.</p>
<h3 id="힙의-특징">힙의 특징</h3>
<ul>
<li>우선순위가 높은 요소가 먼저 나가는 특징을 가진다.</li>
<li>루트가 가장 큰 값이 되는 최대 힙(Max heap)과 루트가 가장 작은 값이 되는 최소 힙(Min heap)이 있다.</li>
<li>자바스크립트에선 직접 구현해서 사용해야 한다.</li>
</ul>
<p>힙은 추가,삭제가 핵심 로직이다.</p>
<h3 id="힘-요소-추가-알고리즘">힘 요소 추가 알고리즘</h3>
<ul>
<li>요소가 추가될 때는 트리의 가장 마지막에 정점에 위치한다.</li>
<li>추가 후 부모 정점보다 우선순위가 높다면 부모 정점과 순서를 바꾼다.</li>
<li>이 과정을 반복하면 결국 가장 우선순위가 높은 정점이 루트가 된다.</li>
<li>완전 이진 트리의 높이는 log N이기에 힙의 요소 추가 알고리즘은 O(log N) 시간 복잡도를 가진다.</li>
</ul>
<h3 id="힙-요소-제거-알고리즘">힙 요소 제거 알고리즘</h3>
<ul>
<li>요소 제거는 루트 정점만 가능하다.</li>
<li>루트 정점이 제거된 후 가장 마지막 정점이 루트에 위치한다.</li>
<li>루트 정점의 두 자식 정점 중 더 우선순위가 높은 정점과 바꾼다.</li>
<li>두 자식 정점이 우선순위가 더 낮을 때 까지 반복한다.</li>
<li>완전 이진 트리의 높이는 log N이기에 힙의 요소 제거 알고리즘은O(log N)시간복잡도를 가진다.</li>
</ul>
<h3 id="js-코드로-구현최대힙">JS 코드로 구현(최대힙)</h3>
<pre><code class="language-js">class MaxHeap {
  constructor() {
    this.heap = [null]; // 인덱스 위치를 1로 시작하기 편하기 0번 위치는 null 로 할당.
  }

  push(value) {
    this.heap.push(value); //처음에 맨 마지막에 값을 넣어준다.
    let currentIndex = this.heap.length - 1; //추가된 값 위치.
    let parentIndex = Math.floor(currentIndex / 2); //추가된 노드의 부모노드의 위치

    while (parentIndex !== 0 &amp;&amp; this.heap[parentIndex] &lt; value) {
      // 부모 위치가 0보다 작지 않으면서 부모노드가 새로추가된 값보다 작을때까지 while문 실행.
      const temp = this.heap[parentIndex]; // 임시값으로 부모노드 값 가져온다.
      // 부모노드와 자식노드 스왑.
      this.heap[parentIndex] = value;
      this.heap[currentIndex] = temp;
      // 다음 부모 노드를 찾기위해서 현재노드위치와 부모노드 위치 스왑.
      currentIndex = parentIndex;
      parentIndex = Math.floor(currentIndex / 2);
    }
  }

  pop() {
    const returnValue = this.heap[1]; // root노드 가져오기.
    this.heap[1] = this.heap.pop(); // 맨마지막 노드를 pop하고 rootnode로 삽입.

    let currentIndex = 1;
    let leftIndex = 2;
    let rightIndex = 3;
    while (
      this.heap[currentIndex] &lt; this.heap[leftIndex] ||
      this.heap[currentIndex] &lt; this.heap[rightIndex]
    ) {
      // 현재 부모노드가 자기 자식노드(왼쪽노드, 오른쪽노드) 둘중 하나의 값보다 작을때 까지 while문 실행
      if (this.heap[leftIndex] &lt; this.heap[rightIndex]) {
        // 오른쪽이 왼쪽보다 클때 부모노드와 오른쪽노드와 스왑.
        [this.heap[currentIndex], this.heap[rightIndex]] = [
          this.heap[rightIndex],
          this.heap[currentIndex],
        ];
        currentIndex = rightIndex;
      } else {
        [this.heap[currentIndex], this.heap[leftIndex]] = [
          this.heap[leftIndex],
          this.heap[currentIndex],
        ];
        currentIndex = leftIndex;
      }
      leftIndex = currentIndex * 2;
      rightIndex = currentIndex * 2 + 1;
    }
    return returnValue;
  }
}
const heap = new MaxHeap();
heap.push(45);
heap.push(36);
heap.push(54);
heap.push(27);
heap.push(63);
console.log(heap.heap); //[ null, 63, 54, 45, 27, 36 ]

const array = [];
array.push(heap.pop());
array.push(heap.pop());
array.push(heap.pop());
array.push(heap.pop());
array.push(heap.pop());
console.log(array); //[ 63, 54, 45, 36, 27 ]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[GET과POST 차이]]></title>
            <link>https://velog.io/@sungmin-choi/GET%EA%B3%BCPOST-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@sungmin-choi/GET%EA%B3%BCPOST-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Sat, 02 Apr 2022 10:11:32 GMT</pubDate>
            <description><![CDATA[<h2 id="get특징">GET특징</h2>
<p>GET 요청은 데이터 요청할때만 사용할것.</p>
<p>http 메시지에 body가 없어서 URL에 모든 정보를 담아서 보내야함.</p>
<ul>
<li><p>GET 요청은 캐시가 가능하다.</p>
<p>  GET을 통해 서버에 리소스를 요청할 때 웹 캐시가 요청을 가로채 서버로부터 리소스를 다시 다운로드하는 대신 리소스의 복사본을 반환한다. HTTP 헤더에서 cache-control 헤더를 통해 캐시 옵션을 지정할 수 있다.</p>
</li>
<li><p>GET 요청은 북마크가 가능함.</p>
</li>
<li><p>GET 요청은 브라우저 히스토리에 남는다.</p>
</li>
<li><p>GET 요청은 길이 제한이 있다.</p>
<p>  브라우저마다 제한길이가 다름.</p>
</li>
<li><p>GET 요청은 중요한 정보를 다루면 안된다(보안)</p>
<p>  get 요청은 파라미터에 다 노출하기 때문이다.</p>
</li>
<li><p>GET 요청은 멱등성을 가지고있다.</p>
</li>
</ul>
<h2 id="post특징">POST특징</h2>
<p>POST 요청은 서버에서 리소스를 생성하거나 업데이트 할때 쓸것.</p>
<p>전송할 데이터를 http메시지 body에 담아서 보낸다 (body 타입은 Content-Type 헤더에 따라 결정된다)</p>
<ul>
<li>POST 요청은 캐시되지 않는다.</li>
<li>POST 요청 브라우저 히스토리에 안남는다.</li>
<li>POST 요청 북마크 되지 않는다.</li>
<li>POST 요청은 데이터 길이 제한이 없다.</li>
<li>POST 요청은 멱등이 아니다.</li>
</ul>
<h3 id="멱등성이란">멱등성이란?</h3>
<p>서버의 상태는 멱등성이 유지되어야 하는경우 같은 행위를 여러 번 반복하더라도 같은 효과를 가져야 합니다.</p>
<p>멱등성이 성립하지 않으면, 같은 행위를 여러 번 반복하는 경우 요청마다 다른 효과가 발생된다고 생각하면 되겠죠?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hoisting]]></title>
            <link>https://velog.io/@sungmin-choi/Hoisting</link>
            <guid>https://velog.io/@sungmin-choi/Hoisting</guid>
            <pubDate>Sat, 02 Apr 2022 08:58:02 GMT</pubDate>
            <description><![CDATA[<p>호이스팅은 코드 실행 전에 변수 및 함수 선언을 해당 범위의 맨 위로 이동하는 자바스립트 메커니즘이다.</p>
<p>변수 생성하는데 총 3가지 단계를 걸친다.</p>
<ol>
<li>선언단계: 변수를 변수객체에 등록하는 단계이다 . 해당 변수객체는 스코프 참조대상이된다.</li>
<li>초기화단계: 변수객체 에 있는 변수들 에게 메모리 공간을 확보해주는 단계. 각 변수들 에게 <code>undefined</code> 값을  할당하게 된다.</li>
<li>할당단계: 변수들 에게 새로운값을 할당해주는 단계. </li>
</ol>
<ul>
<li><code>var</code>는 선언과 초기화 가 한번에 이뤄져서 undefined 값을 초기화 하기 때문에. 변수 선언문 전에 접근해도 에러가 발생하지 않고 undefined 값이 출력이 된다.</li>
<li><code>const</code> ,<code>let</code> 은 선언과 초기화 가 분리되어있기 때문에 변수 선언문 까지 도달해야 초기화 가 되기때문에 그전에 변수에 접근하면 참조에러가 뜬다.</li>
</ul>
<p>스코프 시작점 부터 초기화 시작점까지 그 구간을 TDZ 일시적 사각지대라고 부른다. </p>
<ul>
<li>함수선언문 은 선언 과 함수 초기화 가 한번에 이뤄져서 함수 선언문 전에 호출 해도 정상적으로 작동한다 하지만 화살표함수, 함수표현식 은 선언하기 전에 호출하면 참조에러가 뜬다.</li>
</ul>
<p>호이스팅 우선순위:</p>
<p>변수선언이 함수선언보다 우선순위를 가진다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[NGINX + HTTPS 적용하기(우분투)]]></title>
            <link>https://velog.io/@sungmin-choi/NGINX-HTTPS-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0%EC%9A%B0%EB%B6%84%ED%88%AC</link>
            <guid>https://velog.io/@sungmin-choi/NGINX-HTTPS-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0%EC%9A%B0%EB%B6%84%ED%88%AC</guid>
            <pubDate>Wed, 30 Mar 2022 07:01:26 GMT</pubDate>
            <description><![CDATA[<p>Nginx도 하나의 서버다. Nginx 는 정적파일 생성, 리다이렉팅, 캐싱 등 여러가지 기능을 해준다. 그중에 저희는  Nginx를 기반으로 작동하는 웹 서버에 HTTPS를 적용하는 방법에 대해 알아보겠습니다.<img src="https://images.velog.io/images/sungmin-choi/post/385c5c74-fc35-4e06-9dfb-f43ca7cdfdff/n1.png" alt="">
우분투 에서 Nginx 서버랑 Node.js 서버 두개를 서버를 구축 할 것이다.</p>
<p>위 사진은 프론트서버로 예를 들것인데 먼저 저희가 next프레임워크로 구축한 서버를 원래 80번 포트였지만 다시 원래대로 3000포트로 옮기고, nginx 서버를 80번 포트로 실행을 시킬꺼다. 왜냐하면 같은포트로 동시에 두개서버를 열 수 없으니깐 나눠준것이고. 그래서 만약에 외부에서 433포트로 (https 기본포트가 433이다) 로 접근을 하면 nginx 서버가 바로 next포트로 연결을 해 줄것이고. 만약에 외부에서 80번 포트로 접근을 하면 nginx 서버에서 리다이렉트 시켜줘서 433포트로 옮겨서 접근을 시켜 줄 것이다.</p>
<p>앞에 서버하나를 두고 뒤에 또다른서버를 두는 둘 관계를  <strong>리버스 프록시</strong>라고 한다. 리버스 프록시에 대해서는 쫌 더 공부할 예정이다.(nginx 가 next 서버를 리버스 프록시 해준다.)</p>
<h3 id="우분투에-nginx-설치및-설정">우분투에 nginx 설치및 설정</h3>
<h3 id="1-nginx-설치">1. nginx 설치</h3>
<pre><code class="language-bash">$ sudo apt-get install -y nginx </code></pre>
<h3 id="2-nginx-congif-파일-설정-보기">2. nginx congif 파일 설정 보기</h3>
<pre><code class="language-bash">$ vim /etc/nginx/nginx.conf</code></pre>
<p>입력해서 들어가시면 </p>
<p>여러 정보들이 보일겁니다.
<img src="https://images.velog.io/images/sungmin-choi/post/5b0dcf6d-9397-46f0-982a-71825b7f6107/n2.png" alt="">
여기서 저희가 유심히 봐야할 부분은 http 이부분이다.</p>
<p>여기서 http 안에 server에 여러분 도메인(server_name)과 프록시 포트(3000같은 것)로 작성하시면 됩니다.</p>
<p>작성할 내용:</p>
<pre><code class="language-jsx">servser{
    server_name effectshop-htmlcss.ml;
    listen 80;
    location / {
            proxy_set_header HOST $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection &quot;upgrade&quot;;
      proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://127.0.0.1:3000;
            procy_redirect off;
    }
}</code></pre>
<p>server_name은 자신의 프로젝트 도메인네임을 작성하시면 됩니다.</p>
<p>proxy_pass 부분은 자신이 리다렉트하고 싶은 local 포트를 설정해 주시면 됩니다.
<img src="https://images.velog.io/images/sungmin-choi/post/8ac26e68-ee60-454d-bdee-9d4ea60fec8c/n3.png" alt="">
이렇게 추가를 해 주세요.</p>
<h3 id="3-lets-encrypt-를-통해서-무료-ca인증서-발급받기">3. Let’s Encrypt 를 통해서 무료 CA인증서 발급받기</h3>
<p>Let’s Encrypt 를 통해서 3개월 무료 CA인증서를 발급받을 수 있다. 3개월이 만료되면 그때가서 다시 갱신하면 된다.  자동화 갱신은 뒤에서 한번 다뤄 보자 . 자동갱신은 여기 사이트 참조해보자.
<a href="https://www.zerocho.com/category/NodeJS/post/5ef450a5701d8a001f84baeb">제로초 nginx https 적용</a>
설치</p>
<pre><code class="language-bash">$ sudo snap install certbot --classic
$ sudo certbot --nginx</code></pre>
<p>이렇게 해 주시면 자신의 이메일을 입력하고, 약관에 동의한 후 원하는 도메인을 입력하면 인증서가 발급됩니다. 이후 서버를 실행하면 됩니다. </p>
<p>그전에 꼭 port 80번을 비워둬야합니다.</p>
<pre><code class="language-bash">$ sudo lsof -i tcp:80</code></pre>
<p>해당 명령어를 통해서 80번 포트가 할당이 되어있는지 확인하시고 다른 포트가 할당이 되어있다면 kill 해주시고 nginx서버를 80번으로 켜 줘야합니다.
<img src="https://images.velog.io/images/sungmin-choi/post/21101ef7-41d0-44c0-98b4-3254996f610e/n4.png" alt="">
nginx 에러장면 보시면 80포트가 이미 노드가 쓰고있다는걸 확인할 수 있습니다 해당 node 서버를 kill 해 줍시다.</p>
<pre><code class="language-bash">$ sudo npx pm2 kill //모든 pm2 로 실행한 포트 kill 합니다.</code></pre>
<p><img src="https://images.velog.io/images/sungmin-choi/post/0355bb70-12d0-41aa-94a0-5358c486e39e/n5.png" alt="">
다시 80번포트에 다른서버가 구동되는지 확인하시고 없으시면 </p>
<pre><code class="language-bash">$ sudo certbot --nginx</code></pre>
<p>다시 입력 해 주시고 도메인 설정하시고 보면 성공적으로 되어있습니다.
<img src="https://images.velog.io/images/sungmin-choi/post/01b0da4d-9c8e-47ce-89f7-8503587fdfb2/n6.png" alt="">
위 사진 보시면 해당 공개키랑 개인키의 위치가 나와있다.</p>
<p>다시 /etc/nginx/nginx.conf 부분 들어가서 보시면
<img src="https://images.velog.io/images/sungmin-choi/post/7127143b-d8d7-48f5-9006-1108f10cc70d/n7.png" alt="">
추가적으로 ssl 설정이 추가가 되어있는걸 확인할 수 있습니다.</p>
<h3 id="자동-갱신하기">자동 갱신하기</h3>
<p>cron 사용하여 갱신하기.</p>
<p>vim /etc/cron.d/certbot 파일을 다음과 같이 수정합니다. 파일이 없다면 생성합니다</p>
<pre><code class="language-bash">SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12* * * root certbot -q renew --nginx --renew-hook &#39;service nginx reload&#39;</code></pre>
<p>이리하여 프론트단 https 적용이 끝났습니다.</p>
<p>nginx 간단한 명령어</p>
<pre><code class="language-bash">// 시작
$ sudo service nginx start
$ sudo systemctl start nginx
$ sudo /etc/init.d/nginx start

// 재시작
$ sudo service nginx restart
$ sudo systemctl restart nginx
$ sudo /etc/init.d/nginx restart

// 중지
$ sudo service nginx stop
$ sudo systemctl stop nginx
$ sudo /etc/init.d/nginx stop

// 상태
$ sudo service nginx status
$ sudo systemctl status nginx

// 설정 reload
$ sudo service nginx reload
$ sudo systemctl reload nginx
$ sudo nginx -s reload

// 설정파일 문법 체크
$ sudo nginx -t

// 재시작 전에 80번 포트 중지
$ sudo fuser -k 80/tcp</code></pre>
<p>express프레임워크를 사용하는경우 </p>
<p>app.js 아네 app.set(&#39;trust proxy&#39;, 1); <em>//프록시 뒤에 express 사용할 때 해줘야하는 설정.추가를 해주자.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PM2 사용하기 ]]></title>
            <link>https://velog.io/@sungmin-choi/PM2-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sungmin-choi/PM2-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 30 Mar 2022 06:54:54 GMT</pubDate>
            <description><![CDATA[<p>foreground process</p>
<p>터미널 끄면 같이 꺼지는 형상을</p>
<p>background process </p>
<p>터미널 꺼도 안 꺼지게 설정해야함</p>
<ul>
<li>우분투에서는 포트1024 밑으로 내려가는 포트들은 다 사용자 권한이 있어야 실행시킬 수 있다. 그래서 80번 포트로 우분투에서 서버를 실행 시킬려면 sudo로 시작해야함</li>
</ul>
<p>pm2 라이브러리를 설치하여 터미널이 꺼져도 서버가 안꺼지게끔 설정이 가능하다.</p>
<p>그리고 여러기능이 포함되어있어 여러므로 편리하다.</p>
<p>백에포함된 package.json “start” 부분을 이렇게 바꿔줍니다.</p>
<pre><code class="language-json">&quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;,
    &quot;dev&quot;: &quot;nodemon app.js&quot;,
    &quot;start&quot;: &quot;cross-env NODE_ENV=production pm2 start app.js&quot;
  },</code></pre>
<p>sudo npx pm2 start app.js : 서버 background process 로 진행하기.</p>
<p>sudo npx pm2 kill : 서버 끄기.</p>
<p>sudo npx pm2 reload all: 서버를 다시 재시작.</p>
<p>sudo npx pm2 monit : 서버상태 확인.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Event Loop]]></title>
            <link>https://velog.io/@sungmin-choi/Event-Loop</link>
            <guid>https://velog.io/@sungmin-choi/Event-Loop</guid>
            <pubDate>Sun, 20 Mar 2022 11:24:17 GMT</pubDate>
            <description><![CDATA[<h1 id="event-loop">Event Loop</h1>
<p>자바스크립트는 싱글쓰레드기반 언어이기때문에 한번에 여러작업을 처리할 수 없습니다. 하지만 실제로 웹 애플리케이션에서는 동시에 여러가지작업을할 수 있는 것처럼 느껴진다. 이처럽 자바스크립트를 동시성을 지원하는 것이 바로 브라우저에서 지원하는 이벤트루프입니다.(node.js 런타임환경에서도 동시성을 지원해서 비동기가 가능하다). </p>
<h2 id="process란">Process란?</h2>
<p>운영체제에서 CPU자원을 할당받는 작업의 단위입니다. 메모리에 올라와서 실행되고 있는 프로그램의 인스턴스를 의미합니다.</p>
<p>예를들어 음악플레이어나, 사진프리뷰어 등등이 각각의 프로세스를 가지고 있다. 서로 독립적으로 실행된다.</p>
<h3 id="process-구조">Process 구조:</h3>
<ul>
<li>Code: 프로세스를 구동하기 위한 코드들들이 담겨져있다.</li>
<li>Stack: 프로세스에 담겨져있는 함수들이 어떤 순서로 실행이 되어야 하는지 끝나면 어떤식으로 다시 돌아가야하는지에 대한 정보가 저장되어있다.</li>
<li>Heap: 동적으로 데이터나 오브젝트가 생성이 될 때 저장되는 공간.</li>
<li>Data: 전역변수, static 변수들이 저장되어 있다.</li>
</ul>
<h2 id="thread란">Thread란?</h2>
<p>쓰레드는 한 프로세스 안에서 여러개가 동작이 가능하다. 각각 저마다 해야 되는 업무를 배정 받는다. </p>
<p>쓰레드는 자기들만의 수행해야 되는 함수들을 기억해야하기 때문에 쓰레드마다 Stack만 따로 할당 받고 Code, Data, Heap 영역은 공유합니다. 한 프로세스안에 여러개의 스레드가 담겨져 있으면 동시다발 적으로 여러개의 일을 처리 할 수 있게됨 노래들으면서 글 읽으면서 댓글쓰기 등등 여러가지 일을 동시에 수행이 가능함.</p>
<h3 id="멀티-스레드-장점">멀티 스레드 장점:</h3>
<p>티 스레드가 가지는 장점은 첫 번째로 프로세스를 생성하여 자원을 할당하는 시스템 콜이 감소하므로 자원을 효율적으로 관리할 수 있고, 스레드 간의 통신 비용이 더 적게 발생합니다. 대신, </p>
<p>스레드 간에 공유자원으로 인한 문제를 위해 동기화에 대해서 신경을 써줘야 합니다.</p>
<h3 id="자바스크립트-런타임-환경은-간단하게-이렇게-생겼다">자바스크립트 런타임 환경은 간단하게 이렇게 생겼다.</h3>
<p><img src="https://images.velog.io/images/sungmin-choi/post/55b0d286-9fb0-42d0-973e-11afe465a94e/el1.png" alt=""></p>
<h3 id="자바스크립트-엔진">자바스크립트 엔진:</h3>
<p>여기서 memory Heap 과 call Stack 이 담겨져있는 컨테이너는 자바스크립트 엔진이다.</p>
<p>자바스크립트 엔진에서는 크게 Memory Heap 과 Call Stack 등이 있습니다.</p>
<ul>
<li>Memory Heap: 우리가 데이터를 만들때 , 변수를 선언해서 오브젝트를 할당하거나 문자, 숫자등등 을 Memory Heap에 저장이 되어집니다. 메모리 힙은 구조적으로 정리된 자료구조가 아니라 여기저기 흝어져서 저장이 되어있다.</li>
<li>Call Stack: 실행하는 함수에 따라서 쌓이는 공간이다. LIFO 구조</li>
</ul>
<h3 id="web-api-s">Web API s:</h3>
<p>브라우저에서 제공하는 api 브라우저의 멀티 쓰레딩 을 이용한 다양한 일들을 동시에 실행이 가능하게 만든다.DOM, Ajax,Timeout 등이 있다. Call Stack에서 실행된 비동기 함수는 Web API를 호출하고, Web API는 콜백함수를 Callback Queue(Task Queue) 에 밀어 넣는다.</p>
<h3 id="callback-queuetask-queue">Callback Queue(Task Queue)</h3>
<p><strong><em>비동기적으로 실행된 콜백함수가 보관</em></strong> 되는 영역이다.예를 들어 setTimeout에서 타이머 완료 후 실행되는 함수(1st 인자),addEventListener에서 click 이벤트가 발생했을 때 실행되는 함수(2nd 인자) 등이 보관된다.</p>
<h3 id="event-loop-1">Event Loop:</h3>
<p>Event Loop는 Call Stack과 Callback Queue의 상태를 체크하여,</p>
<p>Call Stack 이 <strong><em>빈 상태가 되면, Callback Queue의 첫번째 콜백을 Call Stack으로 밀어넣는다.</em></strong> </p>
<p>마이크로 태스크 큐 안에있는 모든 콜백을 호출해서 큐가 빌때까지 callstack에 넣어서 실행한다.</p>
<p>이러한 행위를 브라우저가 종료될때까지 계속진행이 된다.</p>
<h3 id="microtask-queue">Microtask Queue:</h3>
<p>마이크로 태스크 큐는 프로미스에 등록된 콜백 즉 프로미스가 다 실행이 되고나면 그 다음에 then  등록한 콜백함수 ,그리고 mutation observer 웹 API 들어있는 콜백 들이 마이크로 태스크 큐에 담긴다.
<img src="https://images.velog.io/images/sungmin-choi/post/398131ec-e7d1-4619-afdd-d12c399a7f6a/el2.png" alt=""></p>
<h3 id="render">Render</h3>
<p>주기적으로 Render 부분을 호출한다 Request Animation Frame 의 콜백함수들이 해당 큐에 쌓인다  ⇒ Render Tree⇒Layout⇒paint⇒composite 과정을 걸치면서  브라우저 화면을 다시 그려준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[우분투에 node, mysql 설치하기]]></title>
            <link>https://velog.io/@sungmin-choi/%EC%9A%B0%EB%B6%84%ED%88%AC%EC%97%90-node-mysql-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sungmin-choi/%EC%9A%B0%EB%B6%84%ED%88%AC%EC%97%90-node-mysql-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 19 Mar 2022 11:25:51 GMT</pubDate>
            <description><![CDATA[<h3 id="aws통한-배포-두번째-시간-우분투환경에서-nodejs와-mysql-설치">aws통한 배포 두번째 시간 우분투환경에서 node.js와 mysql 설치</h3>
<pre><code class="language-bash">$ sudo apt-get update
$ sudo apt-get install -y build-essential
$ sudo apt-get install curl
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo 
$ sudo apt-get install -y nodejs</code></pre>
<p>해당 코드를 우분투 환경 터미널에다가 한줄한줄 입력해서 node.js 설치를 진행합니다.
<img src="https://images.velog.io/images/sungmin-choi/post/177530e2-c037-4152-9755-174498ec3730/1.png" alt="">
위에 명령어 순서대로 잘 진행을 하셨다면 해당 우분투 환경에서 node 와 npm 이 잘 설치되었다는 것을 확인할 수 있게 됩니다.</p>
<h4 id="현재는-프론트서버-배포-준비중이기-때문에-프론트-폴더에서-진행되는중입니다백엔드-부분도-똑같은-과정으로-진행하시면-됩니다">현재는 프론트서버 배포 준비중이기 때문에 프론트 폴더에서 진행되는중입니다.백엔드 부분도 똑같은 과정으로 진행하시면 됩니다.</h4>
<p>이제 해당 폴더안에 node-modules 를 다운받아 줍시다 명령어는 <code>npm i</code> 로 진행해 주세요.
백엔드 부분도 똑같은 과정으로 ssh링크 가져오셔서 설치를 해주고 node도 설치를 해 줍시다. 백엔드는 mysql 까지 설치해줍시다.<img src="https://images.velog.io/images/sungmin-choi/post/4607dfcd-8399-4ca3-b3ba-ddfebececcd0/2.png" alt="">
백엔드 부분도 잘 설치된게 확인이 되실 수 있습니다.
이어서 <code>npm i</code> 입력해서 해당 폴더에 node-modules 를 다운받아준다.
이어서 다시 front쪽으로 와서 프론트 빌드를 시작하자.(지금 진행중인 프론트 프로젝트는 next.js 프레임워크로 진행중입니다)
<code>$ npm run build</code>  //프론트 터미널에서 입력.
<img src="https://images.velog.io/images/sungmin-choi/post/3d30edb5-d0ba-4abd-bd91-6154092f0952/3.png" alt="">
위 사진 보시다시피 해당 프로젝트는 react프레임워크 next.js 를 통해서 구축을 했기 때문에 빌드가 완성이 되면 이렇게 뜹니다.</p>
<h2 id="백엔드-우분투-터미널-mysql-설치">백엔드 우분투 터미널 Mysql 설치</h2>
<p>다시 백엔드 우분투 터미널로 돌아와서 mysql 를 설치해 봅시다.
<a href="https://tecadmin.net/install-mysql-8-on-ubuntu-18-04/">우분투에서 mysql 8.0 설치</a> 여기서 mysql 8버전 우분투에 설치하는 방법대로 설치를 진행하겠습니다.</p>
<pre><code class="language-bash">$ wget http://repo.mysql.com/mysql-apt-config_0.8.10-1_all.deb
$ sudo dpkg -i mysql-apt-config_0.8.10-1_all.deb 
(받으면 ok 눌러줍시다.)
$ sudo apt update
$ sudo apt install mysql-server
$ sudo su 
(root 계정으로 전환)
$ sudo mysql_secure_installation
(자신의 Mysql 계정비밀번호 설정후 다른 선택사항은 다 yes로 입력해주세요)</code></pre>
<p><img src="https://images.velog.io/images/sungmin-choi/post/099181be-2b51-478b-b6fe-7b7471f89171/4.png" alt="">
root 계정인 상태에서 “mysql -u root -p” 입력하셔서 mysql이 잘 설치가 되었는지 확인해봅시다.사진 보시다시피 잘 설치되었습니다. 아까 설정한 비밀번호는 추후에 한번 바꿔줘야 합니다. 이제 node app.js 를 통해서 우분투에서 back 폴더부분 을 실행시켜보자. 하지만 이런 에러가 뜬다.
<img src="https://images.velog.io/images/sungmin-choi/post/156bd618-3b5f-45f6-93b6-55fa61a459d9/5.png" alt="">
원인은 프로젝트를 깃허브에 push 할때 .env를 같이 안올리기 때문에 해당 프로젝트에 환경변수 설정을 못 읽어오는거 같다.<img src="https://images.velog.io/images/sungmin-choi/post/1eefb8e8-0b74-47a5-a003-cada194d1f58/6.png" alt="">
해당 폴더를 보시면 환경변수 파일 .env 가 없다는것을 알 수 있다. 이제 해당 프로젝트에 .env 파일을 생성하고 안에 환경변수 내용을 추가하면 해결이 될것같다.
생성하기:
“vim .env” 입력 vim 에디터를 통해서 .env 를 만들어주자 
만들고 자신의 환경변수들을 입력해주자.
<img src="https://images.velog.io/images/sungmin-choi/post/590da043-f6f9-4cc6-9787-777a9dbe4271/7.png" alt="">
.env 생성이 잘 됫다는것을 확인할 수 있다. 다시 “node app.js” 로 실행시켜보자. 이제는 다른 에러가 뜬다.
<img src="https://images.velog.io/images/sungmin-choi/post/26b94b14-23f8-409e-a208-32175b61c0be/8.png" alt="">
mysql 비밀번호가 문제가 생긴거 같다.
검색을 한 결과 mysql 비밀번호를 다시 한번 바꿔야한다고 하신다...
비밀번호 바꾸는 방법은:</p>
<blockquote>
<ol>
<li>sudo su 입력해서 root 로 전환</li>
<li>mysql -u root -p 입력해서  mysql로 접근하기 </li>
<li>ALTER USER ‘root’@’localhost’ IDENTIFIED WITH mysql_native_password BY ‘자신비밀번호’</li>
<li>다시 back 폴더로 옮겨가서 npx sequelize db:create; 입력해서 db를 생성해 줍시다.</li>
<li>다시 node app.js</li>
</ol>
</blockquote>
<p>결과:
<img src="https://images.velog.io/images/sungmin-choi/post/676ef27a-ac3a-4539-bf54-d218ce1fa388/9.png" alt="">
성공적인 db 연결!</p>
<h3 id="소스코드-가-업데이트-했을경우">소스코드 가 업데이트 했을경우</h3>
<blockquote>
<ol>
<li>먼서 업데이트된 소스들을 자기 깃허브에 소스코드를 푸쉬해준다.</li>
<li>해당 우분투 터미널 프론트,백 다이렉토리로 이동해서 git pull 명령어 쳐 주시면 코드가 업데이트 됩니다.</li>
<li>프론트는 npm run build 해서 다시 새로운 코드를 빌드하시면 됩니다.(만약 패키지를 새로 설치를 했으면 빌드전에 npm i 를 입력해 새로운 패키지들을 우분투 환경으로 다운을 받는다)</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[비동기(Asynchronous)]]></title>
            <link>https://velog.io/@sungmin-choi/%EB%B9%84%EB%8F%99%EA%B8%B0Asynchronous-u4bt76pk</link>
            <guid>https://velog.io/@sungmin-choi/%EB%B9%84%EB%8F%99%EA%B8%B0Asynchronous-u4bt76pk</guid>
            <pubDate>Thu, 17 Mar 2022 16:12:24 GMT</pubDate>
            <description><![CDATA[<h1 id="asynchronous"><strong>Asynchronous</strong></h1>
<h3 id="비동기란">비동기란?</h3>
<p>비동기방식은 현재 작업의 응답과 다음 작업의 요청이 동시에 진행되지 않아도 되는 것으로 응답에 관계없이 바로 다음 동작이 실행되는 것을 말한다</p>
<h3 id="ajax란">AJAX란?</h3>
<p>자바스크립트를 이용해 비동기적으로 서버와 브라우저가 데이터를 교환할 수 있는 통신 방식이다.</p>
<h3 id="promise란">Promise란?</h3>
<p>비동기처리를 위해서 사용되는 패턴이다. callback 함수를 보완하기 위해서 나온게 Promise다 es6부터 사용하기 시작했다 </p>
<p>Promise는 생성자 함수를 통해서 인스턴스화를 한다.(Pending 상태) </p>
<p>비동기처리 성공하면 resolve메소드를 호출해서 비동기 처리 결과를 후속처리 메소드로 전달한다.(Fulfilled)</p>
<p>비동기처리 실패하면 reject메소드를 호출해서 에러메시지를 후속처리 메소드로 전달한다.(rejected)</p>
<p>후속처리 메소드는 then과catch가 있다. 둘다 프로미스를 반환한다.</p>
<p>then 을 가지고 메소드 체이닝을 통하여서 콜백헬 문제를 해결한다.</p>
<h3 id="asyncawait-">Async,await ?</h3>
<p>Promise를 더욱 쉽게 사용할 수 있도록 ES2017(ES8) 문법이다.</p>
<p>함수의 앞부분에 async 키워드를 추가하고, 함수 내부에서 Promise의 앞부분에 await 키워드를 사용한다.</p>
<p>async, await를 사용할 경우 코드가 간결해지지만, 에러처리를 잡기 위해 try catch를 사용해야한다. 동기적인 코드흐름으로 개발이 가능하다.</p>
<p>예외처리 까다로운점</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP와 HTTPS의 차이와 HTTPS 암호화 방식.]]></title>
            <link>https://velog.io/@sungmin-choi/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%99%80-https%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%96%88%EC%9D%84-%EB%95%8C%EC%9D%98-%EC%9E%A5%EC%A0%90%EC%9D%80</link>
            <guid>https://velog.io/@sungmin-choi/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%99%80-https%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%96%88%EC%9D%84-%EB%95%8C%EC%9D%98-%EC%9E%A5%EC%A0%90%EC%9D%80</guid>
            <pubDate>Thu, 17 Mar 2022 16:09:17 GMT</pubDate>
            <description><![CDATA[<h3 id="http란">HTTP란?</h3>
<p>Hyper Text Transfer Protocol 의 약어로 서로다른 시스템들 사이에서 통신을 주고받게 하는 가장 기본적인 프로토콜 (서버에서 브라우저로 데이터 전송하는 용도로 가장 많이 사용한다)</p>
<h3 id="https란">HTTPS란?</h3>
<p>HTTPS(HyperText Transfer Protocol Secure)는 기존 프로토콜(컴퓨터 사이의 데이터 교환 방식 규칙 정의)에서 데이터가 쉽게 도난 당할 수 있는 것을 방지하기 위해서 SSL(보안 소켓)을 사용하면서 브라우저와 서버 사이에 안전하게 암호화된 연결을 만들 수 있게 도와줍니다. </p>
<p>여기서 중요한게 HTTPS 는 HTTP 자체를 암호화 하는게 아닙니다 . HTTP 프로토콜를 사용해서 운반되는내용을 암호화하는 것입니다. </p>
<p>또한 TLS(전송 계층 보안) 프로토콜을 통해서도 보안을 유지합니다. </p>
<p>TLS는 데이터 무결성을 제공하므로 데이터가 전송 중에 손상되거나 수정되는 것을 방지합니다.</p>
<p>또한, HTTPS의 장점은 검색엔진 최적화(SEO에 도움이 됩니다. 구글과 같은 포털에서는 HTTPS를 사용하는 웹 사이트에 가산점을 부여합니다. 별개로 주소창 옆에 HTTPS가 아니라면 주의 요함 과 같은 경고 문구가 있는데 사용자 측면에서도 자주 들어가고 싶지 않겠지요.</p>
<h3 id="ssltls란">SSL/TLS란?</h3>
<p>TLS는SSL의 업그레이드 버전이라고 보면 된다. 결국 똑같은것을 얘기하는 것이다.</p>
<p>SSL은 Secure Sockets Layer의 약자로 웹 서버와 웹 브라우저간의 보안을 위해 만든 프로토콜이다. <strong>공개키/개인키</strong>, <strong>대칭키</strong> 기반으로 사용된다.</p>
<h3 id="대칭키란">대칭키란?</h3>
<p>동일한키로 암호화와 복호화를 수행하는 것을 말합니다.</p>
<p>대칭키는 암호화와 복호화가 쉽다는 장점을 가지고있습니다.하지만 키를 배송할때 문제가 된다는 단점이 있습니다 (해커가 키를 가로채기만하면 암호화된 정보를 복호화해서 볼수 있기 때문이다) </p>
<h3 id="공개키란">공개키란?</h3>
<p>서로다른키(공개키, 개인키)로 암호화 복호화를 수행하는 방법입니다.  공개키로 암호화를 하고 개인키로 복호화를 한다. 공개키를 전송할때 중간에 해커가 가로채도 아무런 영향이 없음 암호화가 훌륭함 하지만 공개키 방식은 암호화 연산시간이 길어 비용이 크다. </p>
<p>SSL은 그래서 공개키와 대칭키의 의 단점을 보완하기 위해서 두방식을 골고루 사용해서 보안을 지킨다</p>
<h3 id="ssl-통신과정">SSL 통신과정</h3>
<p>가장 먼저 신뢰성을 위한 CA인증서를 사용합니다 </p>
<ol>
<li>먼저 서버의 공개키를 CA에다가 등록하여 CA의 개인키를 통해서 공개키 인증서를 발급받는다(인증이 된 경우에만) CA의 공개키는 브라우저에 자체 내장이 되어있습니다. </li>
<li>클라이언트가 서버에게 접속요청을 했을 때 서버는 클라이언트에게 인증기관에서 받은 인증서를 보내준다.</li>
<li>클라이언트는 브라우저에 내장된 공개키로 해당 인증서를 검증한다. 검증이 된후에 서버의 공개키는 클라이언트의 대칭키로 암호화를 진행해서 암호화된 대칭키를 서버에게 보냄.</li>
<li>서버는 클라이언트의 암호화된 대칭키를 자신의 개인키로 복호화해서 대칭키를 얻어낸다.</li>
<li>클라이언트와 서버는 복호화한 대칭키로 서로 데이터를 주고받는다.</li>
</ol>
<h3 id="http-특성">http 특성</h3>
<p>Stateless: http 통신에서 서버는 클라이언트의 상태를 저장하지 않는다. 클라이언트의 상태를 저장하지 않는다는 말은 클라이언트가 전에 했던 요청이 무엇인지에 따라 반응이 달라지지 않는다는 것이지.</p>
<p>초기 버전(HTTP 1.0) : <code>비-연결지향(Connectionless)</code></p>
<ul>
<li>HTTP 통신을 한 번 할때마다 TCP에 의해 연결-종료를 할 필요가 있었습니다. <strong>한번 Request, Response를 주고받으면 연결을 끊음</strong></li>
<li>서버의 부담을 줄일 수 있지만, 리소스 요청시마다 오버헤드가 발생해 더 많은 부하를 발생시킬 가능성이 있습니다.</li>
<li>Request Header의 Connection 속성에 keep-alive를 적용해 연결 상태를 유지할 수 있습니다.</li>
</ul>
<p>현재 버전(HTTP 1.0 이후) : <code>지속 연결(Persistent Connections)</code>, <code>파이프라이닝(Pipelining)</code></p>
<ul>
<li>서버 또는 클라이언트에서 명시적으로 연결을 종료하지 않는 이상 TCP 연결(TCP Connection)을 계속 유지합니다.</li>
<li>TCP 연결/해제를 위한 오버헤드가 줄어, 서버에 대한 부하가 경감됩니다.</li>
<li>HTTP Request, Response가 빠르게 완료되기 때문에, 웹 페이지를 빨리 표시할 수 있습니다.</li>
<li>HTTP <code>파이프라이닝(Pipelininig)</code> 기능이 추가되어 Request를 병행해서 보내는 것이 가능해졌습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[쿠키,세션,로컬스토리지,세션스토리지]]></title>
            <link>https://velog.io/@sungmin-choi/%EC%BF%A0%ED%82%A4%EC%84%B8%EC%85%98%EB%A1%9C%EC%BB%AC%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80%EC%84%B8%EC%85%98%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80</link>
            <guid>https://velog.io/@sungmin-choi/%EC%BF%A0%ED%82%A4%EC%84%B8%EC%85%98%EB%A1%9C%EC%BB%AC%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80%EC%84%B8%EC%85%98%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80</guid>
            <pubDate>Thu, 17 Mar 2022 15:43:24 GMT</pubDate>
            <description><![CDATA[<h2 id="쿠키">쿠키:</h2>
<p>쿠키는 클라이언트 로컬에 저장되는 키와 값이 들어있는 작은 문자열 파일(4kb)이다.</p>
<p>쿠키는 클라이언트의 상태 정보를 로컬에 저장했다가 참조합니다.</p>
<p>HTTP 요청마다 포함되어 API 호출의 부담으로 작용할 수 있습니다.</p>
<p>사용자 인증이 유효한 시간을 명시할 수 있다, 유효 시간이 정해지면 브라우자가 종료되어도 인증이 유지된다.</p>
<p>HTTP 요청마다 쿠키는 HTTP header에 정보를 담아서 서버로 보내준다. 왜 매번 보내는걸까?</p>
<p>그 이유는 HTTP 프로토콜이 비연결성, 무상태성 한 특성이 있기 때문이다.</p>
<p>이 때 쿠키에 나에 대한 정보를 담아서 서버로 보내면 서버는 쿠키를 읽어서 내가 누군지 파악해야하기 때문이다. </p>
<p>그래서 쿠키는 처음부터 서버와 클라이언트 간의 지속적인 데이터 교환을 위해 만들어졌기 때문에 서버로 계속 전송이 된다.</p>
<p>여디서 문제가 생긴다 매번 쿠키전송으로 인한 웹 애플리케이션 성능저하뿐더러 만약 4kb 용량 제한을 거의 다 채운 쿠키가 있다면, 요청을 할 때마다 기본 4kb의 데이터를 사용해야함. 4kb 중에는 서버에서 필요하지 않는 정보들도 같이 보내질 수 있기때문에 데이터 낭비가 발생한다.</p>
<p>그럴때 필요한게 바로 <code>로컬 스토리지</code>와 <code>세션 스토리지</code>다</p>
<h3 id="쿠키에-문제점">쿠키에 문제점:</h3>
<ol>
<li><p>CSRF 사용자의 권한을 이용한 공격 </p>
<p> 매번 서버에 요청할때마다 쿠키가 전송된다는 점을 활용해서 해커가 쿠키에게 악성 스크립트를 실행시켜 비벌번호 변경이나 결제요청을 하는등 위험할 수 있음.
 (SameSite 설정으로 해결가능) 같은 도메인의 요청만 쿠키를 전송가능하게끔 설정.</p>
</li>
<li><p>XSS </p>
<p> CSRF 와 같은 맥락으로 악성 스크립트를 실행시켜 사용자의 민감한 정보를 탈취한다.
 (httpOnly 설정으로 스크립트접근 차단 가능)</p>
</li>
<li><p>부족한 용량 (위에서 설명)</p>
</li>
<li><p>매번 HTTP 요청시 자동으로 쿠키정보 전송 (위에서 설명)  트래픽 증가.</p>
</li>
</ol>
<h2 id="로컬-스토리지">로컬 스토리지:</h2>
<p>가장 큰 특징으로는 브라우저 창을 닫더라도 데이터가 유지됩니다. 장점은 서버에 불필요한 데이터를 저장하지 않는 다는 점입니다.</p>
<p>그리고 브라우저마다 차이는 있지만 용량이 약 5MB로 매우 큽니다. HTML5를 지원하지 않는 브라우저에서는 사용할 수 없습니다.</p>
<p>자동로그인 사용자 설정, 글 임시저장 브라우저 다크모드 등등을 저장할때 활용하는것이 좋다.</p>
<h2 id="세션-스토리지">세션 스토리지:</h2>
<p>가장 큰 특징으로는 브라우저 창을 닫는 순간 영구적으로 데이터가 삭제됩니다.</p>
<p>세션스토리지도 마찬가지로 서버에 불필요한 데이터를 저장하지 않고, 용량이 5MB로 매우 크고 HTML5를 지원하지 않는 브라우저에서는 사용할 수 없습니다.</p>
<p>주로 폼 정보나 장바구니 정보 등 휘발성이 강한 개인적인 내용을 담는다.</p>
<h3 id="웹-스토리지-특성">웹 스토리지 특성</h3>
<ul>
<li>이 두 저장소의 데이터는 서버로 자동 전송되지 않는다.</li>
<li>두 스토리지는 모두 window 객체 안에 들어 있다. <strong>Storage</strong>객체를 상속받기 때문에 메소드가 공통적으로 존재.(브라우저 구조면에서는  Data persitance 에 저장이 된다)</li>
<li>쿠키랑 똑같이 문자열로 저장이된다. (직렬화를 통해서 객체도 저장이 가능하다)</li>
<li>도메인 별<strong>용량 제한</strong>도 있음(프로토콜, 호스트, 포트가 같으면 같은 스토리지를 공유)</li>
</ul>
<h2 id="쿠키와-웹스토리지-정리">쿠키와 웹스토리지 정리</h2>
<p>쿠키와 웹 스토리지는 보안 문제가 있기 때문에 민감한 정보는 정장하지않는걸 추천드립니다. </p>
<p>쿠키는 서버와 소통할때 필요한 데이터들을 저장하는게 좋고</p>
<p>세션 스토리지는 탭 종료시 삭제되어도 괜찮은 이전페이지, 이전 스크롤 위치 저장등등 을 저장하는데 좋고</p>
<p>로컬 스토리지는 사용자 설정, 글 임시저장 브라우저 다크모드 등등을 저장할때 활용하는것이 좋다.</p>
<h2 id="세션">세션:</h2>
<ul>
<li>세션은 쿠키를 기반하고 있지만, 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버 측에서 관리</li>
<li>서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하며 웹 브라우저가 서버에 접속해서 브라우저를 종료할 때까지 인증상태를 유지</li>
<li>물론 접속 시간에 제한을 두어 일정 시간 응답이 없다면 정보가 유지되지 않게 설정이 가능</li>
<li>사용자에 대한 정보를 서버에 두기 때문에 쿠키보다 보안에 좋지만, 사용자가 많아질수록 서버 메모리를 많이 차지하게 됨.</li>
<li>즉 동접자 수가 많은 웹 사이트인 경우 서버에 과부하를 주게 되므로 성능 저하의 요인이 됨.</li>
<li>클라이언트가 Request를 보내면, 해당 서버의 엔진이 클라이언트에게 유일한 ID를 부여하는 데 이것이 세션ID.</li>
</ul>
<h3 id="세션의-동작-방식">세션의 동작 방식</h3>
<ol>
<li>클라이언트가 서버에 접속 시 세션 ID를 발급.</li>
<li>클라이언트는 세션 ID에 대해 쿠키를 사용해서 저장하고 가지고 있음</li>
<li>클라리언트는 서버에 요청할 때, 이 쿠키의 세션 ID를 서버에 전달해서 사용.</li>
<li>서버는 세션 ID를 전달 받아서 별다른 작업없이 세션 ID로 세션에 있는 클라언트 정보를 가져옴.</li>
<li>클라이언트 정보를 가지고 서버 요청을 처리하여 클라이언트에게 응답.</li>
</ol>
<h3 id="세션의-특징">세션의 특징</h3>
<ul>
<li>각 클라이언트에게 고유 ID를 부여</li>
<li>세션 ID로 클라이언트를 구분해서 클라이언트의 요구에 맞는 서비스를 제공</li>
<li>보안 면에서 쿠키보다 우수</li>
<li>사용자가 많아질수록 서버 메모리를 많이 차지하게 됨.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[EffectShop PostForm 버그 수정.]]></title>
            <link>https://velog.io/@sungmin-choi/EffectShop-PostForm-%EB%B2%84%EA%B7%B8-%EC%88%98%EC%A0%95</link>
            <guid>https://velog.io/@sungmin-choi/EffectShop-PostForm-%EB%B2%84%EA%B7%B8-%EC%88%98%EC%A0%95</guid>
            <pubDate>Sun, 13 Mar 2022 18:38:00 GMT</pubDate>
            <description><![CDATA[<p>프로젝트 개인 Profile 페이지에서 자신의 Effect효과를 새로 만드는 PostForm 부분에서 css코드를 실시간으로 작성할때 버그가 발생했다.
<img src="https://images.velog.io/images/sungmin-choi/post/7c21892e-81cd-45a6-8ab4-a3fb44aa4861/ezgif.com-gif-maker%20(1).gif" alt="">
CSS CODE textarea 안에다가  “  {  ”  괄호를 제대로 안 닫으면  사진처럼 테스트 결과 보여주는 컴포넌트가 다른 컴포넌트와 겹치는 현상이 생겨났습니다.  이게 아마도 동적으로 css코드를 입력을하면 테스트 결과 보여주는 컴포넌트쪽에서 계속 바뀐 css코드를 업데이트해주는데 그때 정상적인 코드가 안불러와지면 이런 현상이 발생하는듯 하다.
<img src="https://images.velog.io/images/sungmin-choi/post/827edfbf-739a-4cd0-beaf-bac99e3671c9/ezgif.com-gif-maker%20(3).gif" alt="">
추가적인 버그는 “[”대괄호 혹은 “(” 소괄호 를 입력하는순간  페이지의 모든 css가 제대로 작동이 되질 않는걸 볼 수 가 있습니다.</p>
<p>버그 정리:</p>
<ol>
<li>“{” 중괄호 짝이 안맞으면 컴포넌트가 겹쳐지는 버그</li>
<li>“[” 대괄호, “(” 가 CSS Code textarea 에 포함되어있으면 해당 페이지의 css가 제대로 작동이 안된다.</li>
</ol>
<p>예전에 백준에서 풀던 괄호유효성 검사 문제를 떠올리게 됬다. 이렇게 프로젝트에서 알고리즘 문제를 적용하게된 사례는 처음이것 같다.</p>
<p>알고리즘 코드:
추가적인 버그는 “[”대괄호 혹은 “(” 소괄호 를 입력하는순간  페이지의 모든 css가 제대로 작동이 되질 않는걸 볼 수 가 있습니다.</p>
<p>버그 정리:</p>
<ol>
<li>“{” 중괄호 짝이 안맞으면 컴포넌트가 겹쳐지는 버그</li>
<li>“[” 대괄호, “(” 가 CSS Code textarea 에 포함되어있으면 해당 페이지의 css가 제대로 작동이 안된다.</li>
</ol>
<p>예전에 백준에서 풀던 괄호유효성 검사 문제를 떠올리게 됬다. 이렇게 프로젝트에서 알고리즘 문제를 적용하게된 사례는 처음이것 같다.</p>
<p>알고리즘 코드:</p>
<pre><code class="language-js">function isValidCss(code){
  const bracket= [];
  for(let i=0;i&lt;code.length;i++){
      if(code[i]===&#39;{&#39;){
          bracket.push(code[i]);
      }else if(code[i]===&#39;}&#39;){
          if(bracket.length&gt;0){
              bracket.pop()
          }else return false;
      }else if(code[i]===&#39;]&#39; || code[i]===&#39;[&#39; || code[i]===&#39;)&#39; || code[i] === &#39;(&#39;){
          return false;
      }
  }
  if(bracket.length===0) return true;
  else return false;
}</code></pre>
<p>이렇게 cssCode가 들어오면 괄호들만 추출해서 LIFO 방식으로 중괄호에 유효성을 검사하였고 소괄호와대괄호가 코드에 포함이 되어있다면 과감없이 코드는 유효하지않는 false 를 반환하게 작성을 하였다.</p>
<p>실제코드에서 false 일때는 테스트 결과 보여주는 컴포넌트가 업데이트가 안되고 true일때만 결과가 업데이트 되는 방식으로 구현을 하였다.</p>
<p>버그 고친 결과:
<img src="https://images.velog.io/images/sungmin-choi/post/22b33a4c-7aa5-460d-b971-8f6cac22cca9/ezgif.com-gif-maker%20(5).gif" alt="">
css 코드가 유효하지 않을때는 테스트 컴포넌트는 업데이트가 안되는걸 볼수있다. 그리고 중괄호와 대괄호가 입력이 되도 페이지의 css가 깨지는 현상도 고칠 수 있었다. 유효하지 않은 코드인 경우 경고문을 발생시켰다.</p>
<h4 id="느낀점">느낀점:</h4>
<p>처음으로 프로젝트에서 백준에서 풀어본 알고리즘문제로 버그를 수정한거 같아 너무 재밌다고 느꼈다. 버그느 수정했지만 더 효율적인 방법으로 버그를 고칠 수 있는지 더 고민을 해봐야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS를 통한 배포(EC2 생성)]]></title>
            <link>https://velog.io/@sungmin-choi/AWS%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B0%B0%ED%8F%ACEC2-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@sungmin-choi/AWS%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B0%B0%ED%8F%ACEC2-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Fri, 11 Mar 2022 14:10:41 GMT</pubDate>
            <description><![CDATA[<h3 id="1-aws-회원가입">1. aws 회원가입</h3>
<p>aws 사이트 들어가서 회원가입 진행.</p>
<h3 id="2-ec2생성">2. EC2생성</h3>
<p>aws 회원가입이 끝나면 자신만에 주소인 <a href="https://ap-northeast-2.console.aws.amazon.com/">https://ap-northeast-2.console.aws.amazon.com/</a> 주소로 이동해서 </p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/9e55d6e2-d844-4798-83ec-e9ff31a945f6/1.png" alt=""></p>
<p>여기를 클릭하여 EC2 생성 준비를 한다.</p>
<p>들어오시면 AMI선택하는 페이지가 뜬다. 프리티어 사용가능하다는것은 어느정도선에서 서버를 공짜로 쓸 수 있는 서버라고 이해할 수 있다.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/de9ae3c8-f5e5-4436-861e-9ff83ce7f544/2.png" alt=""></p>
<p>저는 여디서 Ubuntu Server 18.04 LTS (프리티어 사용가능) 이걸로 EC2 생성을 하겠다.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/c788ce5a-c2ed-469b-b808-6a94f95c7bf2/3.png" alt=""></p>
<p>들어가시면 인스턴트 유형선택 페이지가 나오는데 여기서 프리티어 사용 가능 표시되어있는 t2.micro 를 사용해서 만들어 보겠다. 비록 메모리랑 CPU 용량이 적지만 개인이 연습용으로 배포하는거면 적합하다고 생각한다. </p>
<p>컴토및시작 클릭.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/15af108d-358f-407e-9bc1-6c79b2dbae4d/4.png" alt="">
보안 그룹 구성 부분에서 </p>
<p>규칙추가 클릭해서 http,https를 추가해주자 포트 는 기본으로 80,443으로 기본값으로 되어있습니다ssh 는 보안상 소수부분 ip 주소는 자기 집주소로 해주는것을 권장한다.</p>
<p>검토및시작 클릭→시작하기 클릭.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/03b1b97c-1057-4f5f-b845-d6e89eb72182/5.png" alt=""></p>
<p>새로운 키 페어 생성한다 키페어 이름은 자기자신 프로젝트이름으로 해도 무방하다.</p>
<p>이름을 다 지은후에 키 페어를 다운받는다 .pem 파일을 다운이 될겁니다.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/61217e9e-da5d-4f27-8451-04f55043fcc3/6.png" alt=""></p>
<p>받은 키페어는 사용자에 전체 프로젝트 파일 하위 디렉토리에 넣어주고 .gitignore에 키 파일을 써줘서 github에 올리는것을 방지한다.</p>
<p>해당 프로젝트는 깃허브를 통해 하나의 repository를 만들어서 올려준다 </p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/f49d0907-ac4a-427e-8b5e-5e4eaf04715b/7.png" alt=""></p>
<p>해당 주소도 기억해두자.</p>
<p>다시 aws로 가셔서 </p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/2663e8a1-3559-46ff-9357-5d25c7538757/8.png" alt=""></p>
<p>EC2 클릭</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/da445ab3-89cb-49f2-ad1e-3db9bc08948e/9.png" alt=""></p>
<p>저는 똑같은 방법으로 같은 키페어안에서 front ,back 이렇게 두개의 인스턴스를 만들었습니다.</p>
<h3 id="3-우분투-서버로-접근해서-프로젝트-폴더-업로드하기">3. 우분투 서버로 접근해서 프로젝트 폴더 업로드하기</h3>
<p>터미널에서 자신의 프로젝트 디렉토리로 이동하기</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/38803240-16c9-4fd5-9419-64d01a842bd7/10.png" alt=""></p>
<p>인스턴트 하나 클릭하고 연결버튼 클릭.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/a1c2f2be-8c41-44e5-9387-0ca356014aea/11.png" alt=""></p>
<p>ssh 클라이언트쪽으로 가셔서</p>
<p>자신만에 ssh -i “effect-shop”..... 명령어를 복사하셔서</p>
<p>터미널에 입력해 줍시다. 저는 mac 운영체제여서 앞에다가 sudo 명령어를 추가해서 입력했습니다.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/daff2ab6-6dd8-4fb3-8dfb-8816b2f5f8a7/12.png" alt=""></p>
<p>yes 입력하시고 성공하시면 우분투 로 터미널이 전환이 됩니다.</p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/575b6045-ce2e-4227-b1ad-89c7cace8576/13.png" alt=""></p>
<p><img src="https://images.velog.io/images/sungmin-choi/post/0dcb3bb7-c7a0-4433-843e-21e268afa7c7/14.png" alt=""></p>
<p>자신의 레파지토리 를 우분투에 git clone 진행한다. 터미널에서 보시면 자신의 프로젝트가 잘 다운받은걸 볼 수있다.</p>
<p>깃허브에 코드가 변경이 된경우 우분투에서도 다시 git pull 명령어로 코드를 업데이트 해줘야한다.</p>
<p>이상으로 1편 마무리.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[EffectShop 에서getStaticProps, getServerSideProp 적용하기]]></title>
            <link>https://velog.io/@sungmin-choi/EffectShop-%EC%97%90%EC%84%9CgetStaticProps-getServerSideProp-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sungmin-choi/EffectShop-%EC%97%90%EC%84%9CgetStaticProps-getServerSideProp-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 09 Mar 2022 12:53:59 GMT</pubDate>
            <description><![CDATA[<p>프로젝트가 어느정도 완성이되가서 이제 next.js 의 강점을 적용해볼 시간이 된듯 하다. 
각 페이지의 용도에따라서 <code>getStaticProps</code> 를 사용할껀지 아니면 <code>getServerSideProps</code>를 사용할껀지 정하고 구현을 했습니다.</p>
<h3 id="1-redux를-nextjs-에서-사용하기-위한-초기-설정">1. redux를 next.js 에서 사용하기 위한 초기 설정</h3>
<p>store/configureStore.js
store 기본 설정 파일에서 의 초기 셋팅</p>
<p>redux를 next.js 서버에서 사용하게끔 할려면 </p>
<pre><code class="language-js">import { createWrapper } from &quot;next-redux-wrapper&quot;;</code></pre>
<p>createWrapper 를 사용해서 기본 configeStore 설정을 감싸고 export 해줘야합니다.</p>
<pre><code class="language-js">const wrapper = createWrapper(configureStore,{
    debug: process.env.NODE_ENV === &#39;development&#39;,
})

export default wrapper;</code></pre>
<p>전체 코드:</p>
<pre><code class="language-js">import { createWrapper } from &quot;next-redux-wrapper&quot;;
import { applyMiddleware, compose, createStore } from &quot;redux&quot;;
import { composeWithDevTools } from &quot;redux-devtools-extension&quot;;
import createSagaMiddleware from &quot;@redux-saga/core&quot;;
import rootSaga from &quot;../sagas&quot;;
import reducer from &#39;../reducers&#39;

const configureStore = () =&gt;{
    const sagaMiddleware = createSagaMiddleware();
    const middlewares = [sagaMiddleware];

    const enhancer = process.env.NODE_ENV === &#39;production&#39; ?
        compose(applyMiddleware(...middlewares)):
        composeWithDevTools(applyMiddleware(...middlewares));

    const store = createStore(reducer,enhancer);
    store.sagaTask = sagaMiddleware.run(rootSaga);
    return store;
}


const wrapper = createWrapper(configureStore,{
    debug: process.env.NODE_ENV === &#39;development&#39;,
})

export default wrapper;</code></pre>
<h3 id="2-home-페이지-gerserversideprops-적용하기">2. Home 페이지 gerServerSideProps 적용하기</h3>
<p>wrapper import 해줘서 밑에처럼 사용해야 redux를 같이 쓸수있다.
Home을 SSR 하는 이유는 </p>
<ul>
<li>Effect들을 페이지와 한꺼번에 깔끔하게 그려줘서 받아오고 싶기 때문에</li>
<li>로그인이 된 상태면 서버에서 미리 로그인상태인걸 확인하고 로그인 상태인 페이지를 그려줘서 화면에 보일 수 있게끔 하기위해서( 초기에는 로그인이 아닌 상태로 클라이언트에 불러와서 <code>LOAD_MY_INFO_REQUEST</code> 요청을 보내 로그인 상태면 다시 로그인 상태로 바꿔주는 뭔가 이질적인 느낌을 느꼇다)<pre><code class="language-jsx">import {LOAD_EFFECTS_REQUEST,FIRST_LOAD_EFFECTS_REQUEST } from &#39;../reducers/effect&#39;
import {LOAD_MY_INFO_REQUEST} from &#39;../reducers/user&#39;
import { useDispatch,useSelector} from &#39;react-redux&#39;
import wrapper from &#39;../store/configureStore&#39;
import axios from &#39;axios&#39;
import {END} from &#39;redux-saga&#39;;
function Home() {
...
}
</code></pre>
</li>
</ul>
<p>export const getServerSideProps = wrapper.getServerSideProps((store) =&gt; async ({ req }) =&gt; {
const cookie = req ? req.headers.cookie : &#39;&#39;;
/*만약에 이미 로그인이 된상태면 req에 정보들이 있을것이다 
거기서 req.headers.cookie 값을 cookie에 할당해준다.
*/ 
  axios.defaults.headers.Cookie = &#39;&#39;;
//그전에 로그인 한 사람의 쿠기를 지우기 위한 과정.</p>
<p>  if (req &amp;&amp; cookie) {
    axios.defaults.headers.Cookie = cookie;
  }
/<em>쿠키와 유저정보(req) 다 정보가 있다면 요청을 보낼때 header에 cookie 
값을 넣어서 서버로 보내준다. 그러면 서버에서 로그인 
유무를 확인하고 유저정보를 반환해준다.</em>/
  store.dispatch(END);
  await store.sagaTask.toPromise();
  //dispatch 가 끝날때 까지 기달려주는 작업코드 (그냥 이렇게 하라고 나와있다 ㅎㅎ..)</p>
<pre><code>
### 3. 로그인페이지, 회원가입페이지
로그인페이지와 회원가입페이지는 동적으로 불러오는 데이터가 없기때문에 따로 선언을 안해줘도 알아서 빌드시점에서 SSG(Static Site Generation) 정적파일로 만들어준다.

### 4. 다이나믹 라우터 페이지 getStaticProps 적용.
`getStaticProps`는 정말 안바뀌는 정적페이지를 빌드시점에 아예 html 로 만들어서 웹에서 요청을 하면 html파일만 보내주면 되게끔 해주는 기능이다 html만 보내주면 되기때문에 굉장히 빠른속도를 자랑한다.
각 effect detail 페이지를 보시면 이펙트 효과와 html코드css코드만 존재하기 때문에 `getStaticProps`를 사용하기 딱 적합하다고 생각한다.
`getStaticProps`와 `getStaticPaths` 같이 써서 구현을 한다.

```js

const Detail= () =&gt; {
  ...
}

export async function getStaticPaths() {
  return {
    paths:[],
      /*미리 빌드시점에서 생성하고 싶은 애들을 paths에 집어넣어서 빌드할때 
    미리 html에 생성이 가능하다.
    */
    fallback: true,
    /*fallback 을 true로 하면 paths에 없는 애들이 로드되면 
    getStaticProps 사용해서 새로운 html 파일을 만들어준다.
    모든 detail들을 처음에 생성하는건 무리가 있기때문에 유동적으로 
    생성하는게 쫌더 효율적이다.
    */
  };
}

export const getStaticProps =wrapper.getStaticProps((store) =&gt; async ({ params }) =&gt; {
  store.dispatch({
    type: LOAD_EFFECT_DETAIL_REQUEST,
    data: params.id
  });
  store.dispatch(END);
  await store.sagaTask.toPromise();
});
  //SSG 만들어주는 코드.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[next.js 에서  styled components 서버사이드 렌더링 적용하기.]]></title>
            <link>https://velog.io/@sungmin-choi/next.js-%EC%97%90%EC%84%9C-styled-components-%EC%84%9C%EB%B2%84%EC%82%AC%EC%9D%B4%EB%93%9C-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sungmin-choi/next.js-%EC%97%90%EC%84%9C-styled-components-%EC%84%9C%EB%B2%84%EC%82%AC%EC%9D%B4%EB%93%9C-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 09 Mar 2022 08:51:02 GMT</pubDate>
            <description><![CDATA[<p>styled-components 는 컴포넌트가 실행이 될때 같이 그려주기 때문에 서버사이드 렌더링으로 불러오는 페이지에서는 css가 안 입혀져서 불러오는 문제가 생긴다. 그래서 styled-components 도 서버에서 같이 그려줘서 가져올 수 있게끔 어느정도 설정이 필요하다.</p>
<h3 id="1-babelrc-파일을-생성해서-설정">1. .babelrc 파일을 생성해서 설정.</h3>
<p>.babelrc 파일을 package.json파일과 같은 경로에다가 생성을 해 준다.</p>
<pre><code class="language-js">{
    &quot;presets&quot;: [&quot;next/babel&quot;],
    &quot;plugins&quot;: [[&quot;styled-components&quot;, 
                 { &quot;ssr&quot;: true,&quot;displayName&quot;: true }]]
}</code></pre>
<h3 id="2-pages-폴더에-_documentjs-생성">2. pages 폴더에 _document.js 생성</h3>
<p>해당 코드 추가해 주기.</p>
<pre><code class="language-js">import Document from &quot;next/document&quot;;
import { ServerStyleSheet } from &quot;styled-components&quot;;

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      // sheet을 사용해 정의된 모든 스타일을 수집
      ctx.renderPage = () =&gt;
        originalRenderPage({
          enhanceApp: (App) =&gt; (props) =&gt;
            sheet.collectStyles(&lt;App {...props} /&gt;),
        });

      // Documents의 initial props
      const initialProps = await Document.getInitialProps(ctx);

      // props와 styles를 반환
      return {
        ...initialProps,
        styles: (
          &lt;&gt;
            {initialProps.styles}
            {sheet.getStyleElement()}
          &lt;/&gt;
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}</code></pre>
<p>이렇게 하면 스타일 적용이 잘 될것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[passport-github ]]></title>
            <link>https://velog.io/@sungmin-choi/passport-github</link>
            <guid>https://velog.io/@sungmin-choi/passport-github</guid>
            <pubDate>Fri, 04 Mar 2022 14:58:57 GMT</pubDate>
            <description><![CDATA[<p>GitHub으로 로그인(GitHub strategy) 저번 포스터에서는 <a href="https://velog.io/@sungmin-choi/passport-local-%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8">passport-loacl를 통한 로그인</a>에 대한 자세한 과정을 다뤄봤다. local이랑 구현하는 방법이 어느정도 차이가 있어서 이렇게 블로그를 작성해본다.</p>
<p>설치:</p>
<pre><code>npm install --save passport-github</code></pre><h3 id="구현">구현</h3>
<p>GitHub OAuth페이지에서 애플리케이션을 등록 후 받은 clientID, clientSecret값을 보안을 위해 환경변수로 설정하여 입력한다.
OAuth페이지에 입력한 callback URL(인증 후 받을 request URL)을 입력한다.</p>
<pre><code class="language-js">module.exports = ()=&gt;{
    passport.use(new GithubStrategy({
        clientID: process.env.GITHUB_CLIENT_ID,
        clientSecret: process.env.GITHUB_CLIENT_SECRETS,
        callbackURL:&quot;http://localhost:3065/user/github/callback&quot;
    },async (accessToken, refreshToken, profile, done)=&gt;{
        try{
            const { name, id, email } = profile._json;
            const user = await User.findOne({
                where:{
                    githubId:id,
                }
            })
            if(!user){
                const newUser = await User.create({
                    email:email?email:null,
                    githubId:id,
                    nickname:name,
                    password:null,
                })
                return done(null,newUser);
            }
            return done(null,user);
        }catch(error){
            console.error(error);
            return done(error);
        }
    }
    ))
}</code></pre>
<h5 id="userrouterjs">userRouter.js</h5>
<pre><code class="language-js">router.get(&#39;/github&#39;,passport.authenticate(&#39;github&#39;));
router.get(&#39;/github/callback&#39;,
           passport.authenticate(&#39;github&#39;,{successRedirect:&#39;http://localhost:3000&#39;}));</code></pre>
<h4 id="passportindexjs">passport/index.js</h4>
<pre><code class="language-js">module.exports = () =&gt;{
    passport.serializeUser((user,done)=&gt;{
        done(null, user.id);
    });

    passport.deserializeUser(async(id, done)=&gt;{
        try{
            const user = await User.findOne({
                where:{
                    id,
                },
            });
            done(null, user);
        }catch(error){
            console.error(error);
            done(error);
        }
    });
    github();
    local();
};</code></pre>
<h3 id="🛠구현하면서-생긴문제">🛠구현하면서 생긴문제:</h3>
<p>github 로그인은 성공적으로 되나 로그인한뒤로 유저정보 가져오기를 구현하기가 너무 힘들었다. 
local 전략이랑 다른점이 github 전략은 이처럼 OAuth페이지에 입력한 callback URL(인증 후 받을 request URL)을 입력한다. callback url 에서 유저정보를 보내준다 그래서 똑같이 axios 요청으로 해서 다시유저정보를 클라이언트로 돌려받을려하면 callback 출저랑 클라이언트 출저가 달라서 cors에러가 뜬다 사실상 서버에서는 로그인이 성공했는데 해당 유저를 바로 callbackURL 에서 클라이언트로 보내는데에 문제가 생기니깐 </p>
<pre><code class="language-js">router.get(&#39;/github/callback&#39;,
           passport.authenticate(&#39;github&#39;,{successRedirect:&#39;http://localhost:3000&#39;}));</code></pre>
<p>이렇게 로그인이 성공하면 그냥 다시 클라이언트 주소로 리다이렉트를 시키고 
다시 페이지가 렌더링이 될때 useEffect를 통해서 다시 클라이언트에서 서버로 유저정보 담김 쿠키정보와 같이 보내준다. 로그인이 되있다면 유저정보를 가져오는 절차를 추가해서 유저정보를 가져오는걸 구현했습니다.</p>
<pre><code class="language-js">export default function Home() {
  const dispatch = useDispatch();
  const {mainEffects,loadEffectsLoading,hasMoreEffects} = useSelector((state)=&gt;state.effect);
  useEffect(()=&gt;{
    dispatch({
      type:LOAD_MY_INFO_REQUEST 
      // 요청을 보내서 유저정보를 가져온다
    })
    .....
  },[])
  ....
  )
}</code></pre>
<h4 id="느낀점">느낀점</h4>
<p>이번 문제해결를 통해서 cookie, session 에대해서 한층 더 깊게 이해하게 되었다. 하지만 아직도 accessToken, refreshToken 에 대해서 잘 알지 못하기 때문에 추가적으로 알아봐서 다른 해결방안을 고민해봐야겠다.</p>
]]></description>
        </item>
    </channel>
</rss>