<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>수학과의 좌충우돌 프로그래밍</title>
    <link>https://ssungkang.tistory.com/</link>
    <description>수학과 학생의 프로그래밍 기 입니다. 제가 공부하면서 함께 알면 좋은 내용이나 유익한 정보들을 올리도록 하겠습니다.</description>
    <language>ko</language>
    <pubDate>Thu, 16 Apr 2026 17:47:02 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ssung.k</managingEditor>
    <image>
      <title>수학과의 좌충우돌 프로그래밍</title>
      <url>https://tistory1.daumcdn.net/tistory/2934565/attach/6f60230505e74b499924daea99f28409</url>
      <link>https://ssungkang.tistory.com</link>
    </image>
    <item>
      <title>[python] Type Hints, python에 타입을 지정한다?</title>
      <link>https://ssungkang.tistory.com/entry/python-Type-Hints</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;정적언어 VS 동적언어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Type Hints&lt;/code&gt; 에 대해서 알아보기 전에 우선 정적언어와 동적언어에 대한 이해가 필요합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정적언어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 시 변수의 타입이 결정&lt;/li&gt;
&lt;li&gt;변수 선언 시 자료형 지정&lt;/li&gt;
&lt;li&gt;C, Java 등의 언어가 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동적언어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;런타임 시 변수의 타입이 결정&lt;/li&gt;
&lt;li&gt;실행 도중 변수에 예상하지 못한 타입이 들어와 Type Error 발생할 수 있음&lt;/li&gt;
&lt;li&gt;python, javascript 등의 언어가 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Type Hints란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python은 대표적인 동적언어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 변수를 선언할 때, 함수가 매개변수를 받을 때 모두 자료형을 지정하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 말한대로 런타임 시 결정되기 때문에 실행 도중에 예상하지 못한 타입이 들어와 Type Error 발생할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Type Hints&lt;/code&gt; 는 이를 방지하고자 타입을 표시하는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이름 그대로 힌트일 뿐이지 타입을 강제화 하지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Type Hints 사용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Type Hints&lt;/code&gt; 를 어떻게 사용하는지 간단한 예제를 통해 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python 3.5에서는 함수의 파라미터와 반환값에 대한 &lt;code&gt;Type Hints&lt;/code&gt; 가 추가되었습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def greeting(name: str) -&amp;gt; str:
    return 'Hello ' + name
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;런타임 중, &lt;code&gt;__annotation__&lt;/code&gt; 을 통해 확인이 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;print(greeting.__annotations__)
# {'name': &amp;lt;class 'str'&amp;gt;, 'return': &amp;lt;class 'str'&amp;gt;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python 3.6에서는 변수에 대한 &lt;code&gt;Type Hints&lt;/code&gt; 가 추가되었습니다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;greeting_message: str = &quot;hello minsung&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 str과 int 외에 Dict, List, Tuple도 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from typing import Dict, List, Tuple

animal_cnts: Dict[str, int] = {
    &quot;dog&quot;: 2,
    &quot;cat&quot;: 1
}

heights: List[int] = [181, 163, 179, 172]


friends: Tuple[str, int, float] = (&quot;minsung&quot;, 26, 180.9)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python 공식문서에 보면 아래와 같은 문구가 있습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해석하자면 파이썬은 계속 동적 언어로 남을거고, &lt;code&gt;Type Hints&lt;/code&gt;는 필수가 되지 않을거라는 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;code&gt;Type Hints&lt;/code&gt;는 유용하게 쓰일 곳이 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Django의 경우, swagger로 API 문서를 자동화할 때도 요긴하게 쓰이고, 코드의 질을 높이기 위한 좋은 방법이 될 수 있습니다.&lt;/p&gt;</description>
      <category>프로그래밍 언어/Python</category>
      <category>PYTHON</category>
      <category>Type Hints</category>
      <category>정적언어와 동적언어</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/345</guid>
      <comments>https://ssungkang.tistory.com/entry/python-Type-Hints#entry345comment</comments>
      <pubDate>Sun, 20 Jun 2021 20:32:51 +0900</pubDate>
    </item>
    <item>
      <title>[WEB] google이 만든 RPC, gRPC란</title>
      <link>https://ssungkang.tistory.com/entry/WEB-google%EC%9D%B4-%EB%A7%8C%EB%93%A0-RPC-gRPC%EB%9E%80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;gRPC란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;gRPC&lt;/code&gt;는 구글에서 개발한 어디서나 실행할 수 있는 오픈소스 고성능 RPC 프레임워크입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RPC는 Remote Procedure Call의 줄임말로 원격 프로시저 호출이라고 합니다. 이는 별도의 원격제어를 위한 코딩없이 다른 주소공간에서 함수나 프로시저를 실행할 수 있게 해주는 프로세스간 통신 기술입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 MSA 구조에서 각각의 서버가 다른 언어와 프레임워크로 개발되었을 경우에도 RPC는 문제 없이 서버간의 통신이 가능해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 기존의 REST 방식의 경우에는, 표준이 없어 파라미터의 응답이 명시적이지 않았을 뿐 아니라 JSON 형태의 데이터를 Serialization하는 비용이 발생한다는 단점이 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RPC는 이러한 문제점까지 해결하며 사용이 많아지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Stub&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RPC의 핵심 개념은 &lt;code&gt;Stub&lt;/code&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버와 클라이언트는 다른 주소 공간을 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 함수호출에 사용되는 매개변수를 변환하는 작업이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안그러면 메모리 매개변수에 대한 포인터가 다른 데이터를 가리키게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 변환을 담당하는 것이 바로 &lt;code&gt;Stub&lt;/code&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Marshalling과 Unmarshalling&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stub은 클라이언트와 서버 각각에 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client Stub은 함수 호출에 사용될 파라미터를 변환합니다. 이를 &lt;code&gt;Marshalling&lt;/code&gt;이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 서버에서 넘어온 결과를 변환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server Stub은 클라이언트가 전달한 매개변수를 역변환합니다. 이를 &lt;code&gt;Unmarshalling&lt;/code&gt; 이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 함수 실행 결과를 변환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RPC의 동작 방식&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;786&quot; data-filename=&quot;10_RPC1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn7J9w/btq7gXiZRk4/qhWu96h5iVynH189WRl2y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn7J9w/btq7gXiZRk4/qhWu96h5iVynH189WRl2y1/img.png&quot; data-alt=&quot;RPC 동작 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn7J9w/btq7gXiZRk4/qhWu96h5iVynH189WRl2y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn7J9w%2Fbtq7gXiZRk4%2FqhWu96h5iVynH189WRl2y1%2Fimg.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;786&quot; data-filename=&quot;10_RPC1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;RPC 동작 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Client가 Client Stub 호출&lt;/li&gt;
&lt;li&gt;Client Stub가 파라미터를 표준 포맷으로 변경&lt;/li&gt;
&lt;li&gt;Client Stub가 transport layer로 Server Stub에게 메세지 전송&lt;/li&gt;
&lt;li&gt;Server Stub은 프로시저 호출&lt;/li&gt;
&lt;li&gt;프로시저가 완료되면 Server Stub으로 반환&lt;/li&gt;
&lt;li&gt;Server Stub가 transport layer로 Client Stub에게 메세지 전송&lt;/li&gt;
&lt;li&gt;Client Stub은 반환 값을 변환하여 Client에게 전달&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;gRPC의 특징&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HTTP/2&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;gRPC&lt;/code&gt; 는 HTTP/2를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 HTTP/1.1에 비해 여러 측면에서 장점을 가지고 있으며 이에 대한 자세한 내용은 아래 링크에서 참고할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;url&quot; href=&quot;https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1623687916019&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[네트워크] HTTP 1.1 VS HTTP 2.0&quot; data-og-description=&quot;들어가기 전에 웹 개발자에게 있어서 HTTP는 빼놓을 수 없죠. HTTP는 1996년 1.0 버전으로 처음 release 되고 1999년 1.1 버전이 등장하였습니다. 그리고 1.1 버전은 HTTP 2.0이 등장하기까지 무려 15년 동안 &quot; data-og-host=&quot;ssungkang.tistory.com&quot; data-og-source-url=&quot;https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20&quot; data-og-url=&quot;https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/g9d6i/hyKy95p5DO/ZPbZDeFOFyU4gH3TI1QxFk/img.jpg?width=550&amp;amp;height=361&amp;amp;face=0_0_550_361,https://scrap.kakaocdn.net/dn/brEQoI/hyKy3YrDe0/eh4T6n6wzwY3Id15KbkFy1/img.jpg?width=550&amp;amp;height=361&amp;amp;face=0_0_550_361,https://scrap.kakaocdn.net/dn/dtJcPH/hyKy70REZJ/LeAhGRlS3AikaQkKoVS91K/img.jpg?width=1052&amp;amp;height=1248&amp;amp;face=267_380_686_838&quot;&gt;&lt;a href=&quot;https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/g9d6i/hyKy95p5DO/ZPbZDeFOFyU4gH3TI1QxFk/img.jpg?width=550&amp;amp;height=361&amp;amp;face=0_0_550_361,https://scrap.kakaocdn.net/dn/brEQoI/hyKy3YrDe0/eh4T6n6wzwY3Id15KbkFy1/img.jpg?width=550&amp;amp;height=361&amp;amp;face=0_0_550_361,https://scrap.kakaocdn.net/dn/dtJcPH/hyKy70REZJ/LeAhGRlS3AikaQkKoVS91K/img.jpg?width=1052&amp;amp;height=1248&amp;amp;face=267_380_686_838');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[네트워크] HTTP 1.1 VS HTTP 2.0&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;들어가기 전에 웹 개발자에게 있어서 HTTP는 빼놓을 수 없죠. HTTP는 1996년 1.0 버전으로 처음 release 되고 1999년 1.1 버전이 등장하였습니다. 그리고 1.1 버전은 HTTP 2.0이 등장하기까지 무려 15년 동안&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ssungkang.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Protocol Buffer&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜 버퍼는 JSON, XML과 마찬가지로 직렬화 데이터 구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜 버퍼는 다른 구조에 비해 데이터의 크기가 작습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예시를 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 데이터를 JSON으로 표현한 경우 82byte의 크기가 사용되었습니다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{ 
  &quot;userName&quot;:&quot;Martin&quot;,
  &quot;favouriteNumber&quot;:1337,
  &quot;interests&quot;:[&quot;daydreaming&quot;,&quot;hacking&quot;] 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이를 프로토콜 버퍼로 표현한다면 33byte로 표현 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;448&quot; data-filename=&quot;10_proto_buffer.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1gTjS/btq7gYoDJlW/O4OB1jhiZ4zJz11fQjBkvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1gTjS/btq7gYoDJlW/O4OB1jhiZ4zJz11fQjBkvK/img.png&quot; data-alt=&quot;protocol buffers&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1gTjS/btq7gYoDJlW/O4OB1jhiZ4zJz11fQjBkvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1gTjS%2Fbtq7gYoDJlW%2FO4OB1jhiZ4zJz11fQjBkvK%2Fimg.png&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;448&quot; data-filename=&quot;10_proto_buffer.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;protocol buffers&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 프로토콜 버퍼가 데이터를 표현하는지 위 그림에 나와있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필드명을 굳이 전부 표시하지 않고 5bit로 field tag에 숫자로 표현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 뒤에 3bit를 통해 type을 명시하며, 그 다음 byte에서는 데이터의 길이를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 처럼 저장되면 사람이 보고 이해할 수 없기 때문에 &lt;code&gt;proto&lt;/code&gt; 확장자를 가진 파일로 데이터에 대한 설명을 명시합니다.&lt;/p&gt;
&lt;pre class=&quot;protobuf&quot;&gt;&lt;code&gt;message Person { 
    required string user_name       = 1; 
    optional int64 favourite_number = 2; 
    repeated string interests       = 3; 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 데이터의 크기를 최소화하고 통신을 더 빠르게 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RPC의 단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gRPC에 대해 알아보고 있지만 gRPC의 단점은 기존 RPC의 단점과 동일하여 이에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인간이 읽기 부적합&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 말한 &lt;code&gt;proto&lt;/code&gt; 파일이 없을 경우에는 사람이 데이터를 해독하기에 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 유저와 직접적으로 소통하는 클라이언트일 경우 RPC 사용하기에 부적절합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 내부 서비스간에 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;proto 문법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;proto&lt;/code&gt; 파일을 작성하기 위한 문법을 숙지해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹프로그래밍/이론</category>
      <category>gRPC</category>
      <category>http/2</category>
      <category>proto</category>
      <category>Protocol Buffer</category>
      <category>Remote Procedure Call</category>
      <category>RPC</category>
      <category>Stub</category>
      <category>web</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/344</guid>
      <comments>https://ssungkang.tistory.com/entry/WEB-google%EC%9D%B4-%EB%A7%8C%EB%93%A0-RPC-gRPC%EB%9E%80#entry344comment</comments>
      <pubDate>Tue, 15 Jun 2021 01:28:04 +0900</pubDate>
    </item>
    <item>
      <title>[WEB] REST API 란</title>
      <link>https://ssungkang.tistory.com/entry/WEB-REST-API-%EB%9E%80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;REST란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;REST&lt;/code&gt;는 Representational State Transfer의 약자로 &lt;b&gt;자원을 정의하고 자원에 대한 주소를 지정하는 방법&lt;/b&gt; 중 하나입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URI를 통해 자원을 명시하고 HTTP method를 통해서 동작을 정의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 설계 방법은 아래에서 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;REST의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 인터페이스&lt;/li&gt;
&lt;li&gt;HTTP 표준만 따른다면, 언어와 플랫폼에 종속되지 않습니다. 안드로이드, IOS, 웹에 종속되지 않습니다.&lt;/li&gt;
&lt;li&gt;Stateless&lt;/li&gt;
&lt;li&gt;서버에서 상태정보를 따로 저장하고 관리하지 않습니다. 이로 인해 서버의 구현이 단순해집니다.&lt;/li&gt;
&lt;li&gt;Cacheable&lt;/li&gt;
&lt;li&gt;HTTP의 인프라를 그대로 사용할 수 있기 때문에 HTTP가 가진 캐시 기능을 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Self-descriptiveness (자체 표현 구조)&lt;/li&gt;
&lt;li&gt;REST API만 보고도 의도하는 바를 명확하게 이해할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Client-Server 구조&lt;/li&gt;
&lt;li&gt;클라이언트와 서버의 역할을 확실히 구분하여 클라이언트와 서버간에 개발해야 할 내용이 명확해지고 의존성이 줄어듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;REST의 단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST의 장점은 특징을 통해 알아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST의 단점은 아래와 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제한적인 HTTP method&lt;/li&gt;
&lt;li&gt;POST, GET, DELETE, PUT 4개의 HTTP로 제한됩니다.&lt;/li&gt;
&lt;li&gt;표준의 부재&lt;/li&gt;
&lt;li&gt;REST API는 표준이 존재하지 않습니다. 그렇기 때문에 클라이언트와 서버 개발자는 API 문서를 통해 소통을 하고 표준을 잡아가게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호환성&lt;/li&gt;
&lt;li&gt;인터넷 익스플로어같은 경우에는 호환이 되지 않아 지원이 안 될 가능성이 존재합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;REST API 설계 기본 규칙&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준은 존재하지 않지만 설계를 위한 기본 규칙은 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 규칙을 잘 지킨 API를 RESTful하다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;슬래시 구분자를 통해 계층 관계를 나타냅니다.&lt;/li&gt;
&lt;li&gt;마지막에는 슬래시 구분자를 포함하지 않습니다.&lt;/li&gt;
&lt;li&gt;언더바 보다는 하이픈을 사용합니다.&lt;/li&gt;
&lt;li&gt;URI는 소문자로 표기한다.&lt;/li&gt;
&lt;li&gt;URI에 파일 확장자를 표기하지 않는다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>웹프로그래밍/이론</category>
      <category>REST</category>
      <category>REST API</category>
      <category>restful</category>
      <category>web</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/343</guid>
      <comments>https://ssungkang.tistory.com/entry/WEB-REST-API-%EB%9E%80#entry343comment</comments>
      <pubDate>Mon, 14 Jun 2021 18:40:24 +0900</pubDate>
    </item>
    <item>
      <title>[WEB] GraphQL, REST API의 대체?</title>
      <link>https://ssungkang.tistory.com/entry/WEB-GraphQL-REST-API%EC%9D%98-%EB%8C%80%EC%B2%B4</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;GraphQL이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GraphQL&lt;/code&gt; 는 Graph Query Language로 facebook에서 개발한 쿼리 언어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GraphQL&lt;/code&gt; 은 기존의 REST API의 단점들을 보안하기 위해 나온 통신 규약으로 REST API와 많이 비교됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API의 어떠한 문제점들을 보안하는지 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;REST API의 한계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API는 간단한 서비스에는 문제가 없지만 서비스와 복잡해질수록 &lt;code&gt;Over-Fetching&lt;/code&gt; 과 &lt;code&gt;Under-Fetching&lt;/code&gt; 문제가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 여러 환경에 맞춰 API를 제공해야하는 것도 쉽지 않은 일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 각 환경에 맞추다보니 비슷한 역할을 하지만 Endpoint가 다른 API가 많이 개발됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Over-Fetching&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Over-Fetching&lt;/code&gt;은 클라이언트의 요구사항보다 더 많은 데이터를 반환하는 경우를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 생각해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 개발자는 User의 여러 정보를 반환하는 API를 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 User의 name 필드만 필요해도 API를 호출해야하고 불필요한 데이터가 많이 넘어오게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Under-Fetching&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Under-Fetching&lt;/code&gt;은 클라이언트에서 원하는 데이터들을 위해 여러 API를 호출하는 것을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;GraphQL을 통한 해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GraphQL&lt;/code&gt;은 이러한 단점들을 모두 해결하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Endpoint를 생성하고 클라이언트에게 필요한 데이터를 직접 쿼리를 통해 호출하게끔 하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 위 &lt;code&gt;Over-Fetching&lt;/code&gt; 같은 문제는 아래와 같은 쿼리로 필요한 데이터만 조회할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;query {
	user(user_id: 1) {
		username
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 &lt;code&gt;Under-Fetching&lt;/code&gt; 도 하나의 query에 여러 데이터를 호출하여 해결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;GraphQL의 장단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API의 문제점을 해결하기 위해 등장하였다고 해서 &lt;code&gt;GraphQL&lt;/code&gt;이 REST API보다 좋다는 건 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 아직까지 현업에서는 REST API를 더 많이 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GraphQL&lt;/code&gt;의 장단점을 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;하나의 Endpoint&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서도 언급했듯이 &lt;code&gt;GraphQL&lt;/code&gt;은 하나의 Endpoint를 갖습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 입장에서도 한 군데로만 요청을 보내면 되고 여러 API를 신경쓰지 않아도 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;400&quot; data-filename=&quot;web_13_1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bznqEU/btq6cTIQet3/2huPnIQcVcfRnwmJX9auLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bznqEU/btq6cTIQet3/2huPnIQcVcfRnwmJX9auLK/img.png&quot; data-alt=&quot;하나의 Endpoint을 가진 GraphQL&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bznqEU/btq6cTIQet3/2huPnIQcVcfRnwmJX9auLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbznqEU%2Fbtq6cTIQet3%2F2huPnIQcVcfRnwmJX9auLK%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;400&quot; data-filename=&quot;web_13_1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하나의 Endpoint을 가진 GraphQL&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최적화된 데이터&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 위에서 언급했던 내용으로서 &lt;code&gt;Over-Fetching&lt;/code&gt; 와 &lt;code&gt;Under-Fetching&lt;/code&gt; 등의 문제가 발생하지 않아 필요한 데이터만, 한 번의 요청으로 가져올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;환경에 종속적이지 않은 API&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOS, Android 와 같은 다른 기종에 대해 별도의 API를 개발할 필요가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;캐싱&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Endpoint를 사용하기 때문에 HTTP에 제공하는 캐싱 전략을 그대로 사용하는 것이 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;code&gt;GraphQL&lt;/code&gt;만의 캐싱 방법이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파일 업로드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GraphQL&lt;/code&gt;은 아직 파일 업로드에 대해서 구체적인 구현 방법이 정의되어 있지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 개발자 스스로 해결해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 업로드만을 위한 분리된 API를 개발하기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GraphQL&lt;/code&gt; 에 대해서 설명을 하다보니 자연스럽게 REST API와 비교하는 내용이 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 &lt;code&gt;GraphQL&lt;/code&gt; 이 REST API의 문제점을 극복하기 위해 등장했다고는 하나 아직까지는 REST API가 더 많이 쓰이고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘의 장단점이 명확하니 상황에 맞춰 적절한 통신 규약을 선택하는게 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹프로그래밍/이론</category>
      <category>API</category>
      <category>graphQL</category>
      <category>GraphQL의 장단점</category>
      <category>Over-Fetching</category>
      <category>REST API</category>
      <category>REST API VS GraphQL</category>
      <category>Under-Fetching</category>
      <category>web</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/342</guid>
      <comments>https://ssungkang.tistory.com/entry/WEB-GraphQL-REST-API%EC%9D%98-%EB%8C%80%EC%B2%B4#entry342comment</comments>
      <pubDate>Mon, 31 May 2021 22:49:35 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] HTTP 1.1 VS HTTP 2.0</title>
      <link>https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가기 전에&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 개발자에게 있어서 HTTP는 빼놓을 수 없죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 1996년 1.0 버전으로 처음 release 되고 1999년 1.1 버전이 등장하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 1.1 버전은 HTTP 2.0이 등장하기까지 무려 15년 동안 지속되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 시간이 지남에 따라 웹에서 담아야 할 정보는 점점 늘어났고, 지금은 하나의 웹사이트에 수 많은 멀티미디어 리소스들과 비동기 요청들이 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서 더 이상 HTTP 1.1은 버티기 힘들었고 HTTP 2.0이 등장하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 HTTP 1.1이 버티기 힘들었으며, HTTP 2.0은 어떤 점이 좋은지 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTTP 1.1이 어떻길래&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HTTP Pipelining&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 1.0은 기본적으로 Connection 당 하나의 요청을 처리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 동시전송은 불가능하고 하나의 요청에 대한 응답이 온 후 다음 요청을 처리하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서도 말했듯이 수 많은 멀티미디어 리소스들이 있는 상황에서 이러한 특징은 Network Latency를 발생시킵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 HTTP 1.1에서 &lt;code&gt;HTTP Pipelining&lt;/code&gt; 이 도입되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 TCP 안에 두 개 이상의 HTTP 요청을 담아 Network Latency을 줄이는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이는 정확히 구현하기 힘들 뿐 아니라 &lt;code&gt;HOL Blocking&lt;/code&gt;이 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HOL Blocking&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HOL은 Head of Line의 줄임말로서 앞선 요청에 의해 뒤에 요청이 지연되는 것을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;HTTP Pipelining&lt;/code&gt; 을 통해 한 번에 여러 개의 이미지를 요청하는 경우를 생각해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 앞에 요청한 이미지가 응답이 지연되면 두, 세번째 이미지도 지연이 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 안에 여러 개의 HTTP 요청이 왔으므로 완료된 응답부터 보내면 되지 않을까라고 생각할 수 있지만 서버는 TCP에서 요청을 받은 순서대로 응답을 해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;무거운 Header&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트와 서버 간에 수 많은 http 요청이 발생할 것이고 header의 정보는 대부분 동일합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 HTTP 1.1에서는 이러한 헤더를 중복해서 계속 보낼 뿐 아니라 cookie 정보 역시 매 요청마다 헤더에 포함되어 전송됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 불필요한 데이터를 주고 받는데 네트워크 자원이 소비되는 문제가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTTP 2.0이 등장하기 이전에&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 2.0이 등장하기 전, 개발자들이 마냥 손 놓고 있지만은 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 1.1 안에서 위에서 봤던 문제점을 극복하기 위해 노력했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Image Spriting&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 이미지 파일들에 대해 각각 요청을 하기 보다 한 번에 요청으로 끝내기를 택했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 이미지를 모아 하나의 큰 이미지를 만든 후, CSS로 해당 이미지의 좌표값을 지정해서 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Domain Sharding&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Domain에 대해 여러 개의 Connection을 생성하여 병렬로 요청을 보냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 브라우저 별로 Domain당 Connection 개수의 제한이 존재하므로 근본적인 해결책이 될 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CSS, Javascript 최소화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송되는 데이터의 용량을 줄이기 위해 CSS, Javascript 파일을 최소화하여 통신합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTTP 2.0의 등장&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 2.0은 HTTP를 아예 새롭게 개선하기 보다는 기존 HTTP 1.1을 개선하는 방향에서, 성능 쪽에 초점을 맞춘 프로토콜로서2015년 2월 표준으로 승인되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 1.1의 여러 문제점으로 구글이 개발한 비표준 개방형 프로토콜 SPDY를 기반하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Multiplexed Streams&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 1.1의 &lt;code&gt;HTTP Pipelining&lt;/code&gt; 의 개선안으로 하나의 Connection으로 동시에 여러 개의 메세지를 주고 받을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 응답은 요청 순서에 상관없이 Stream으로 받기 때문에 &lt;code&gt;HOL Blocking&lt;/code&gt; 도 발생하지 않습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;160&quot; data-filename=&quot;1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N3gTd/btq5ZkrJyPW/TwE04sqB8PlQuOKHAjLlKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N3gTd/btq5ZkrJyPW/TwE04sqB8PlQuOKHAjLlKk/img.png&quot; data-alt=&quot;Multiplexed Streams&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N3gTd/btq5ZkrJyPW/TwE04sqB8PlQuOKHAjLlKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN3gTd%2Fbtq5ZkrJyPW%2FTwE04sqB8PlQuOKHAjLlKk%2Fimg.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;160&quot; data-filename=&quot;1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Multiplexed Streams&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Stream Prioritization&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답에 대한 우선순위를 정해 우선순위가 높을수록 응답을 빨리 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 하나의 HTML 문서에 CSS 파일과 여러 IMG 파일이 있다고 가정해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만일 여러 IMG 파일을 응답하느라 CSS 파일의 응답이 느려지면 클라이언트는 렌더링을 하지 못하고 기다리게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 CSS 파일의 우선순위를 올려 렌더링을 진행하며 IMG 파일은 도착하는 대로 띄어준다면 더 효율적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Server Push&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 클라이언트의 요청없이 응답을 보내는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 마찬가지로 하나의 HTML 문서에 CSS 파일과 여러 IMG 파일이 있다고 가정해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 HTML 문서를 요청한 후 다시 각각의 CSS 파일과 여러 IMG 파일을 위한 요청을 보내야 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;code&gt;Server Push&lt;/code&gt; 로 인해서 클라이언트의 요청을 최소화하고 서버가 리소스를 알아서 보내줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Header Compression&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 1.1의 경우 이전 요청과 중복되는 Header도 똑같이 전송하느라 네트워크 자원을 불필요하게 낭비하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 2.0의 경우, Header Table과 Huffman Encoding을 사용하는 HPACK 압축방식으로 이를 개선하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트와 서버는 각각 Header Table을 관리하고 이전 요청과 동일한 필드는 table의 index만 보내고, 변경되는 값은 Huffman Encoding 후 보냄으로서 Header의 크기를 경령화 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;150&quot; data-filename=&quot;2.svg&quot; width=&quot;465&quot; height=&quot;391&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgdFrZ/btq5YvAfV8N/JCw0ssIHEkhPwNU93VJSz1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgdFrZ/btq5YvAfV8N/JCw0ssIHEkhPwNU93VJSz1/tfile.svg&quot; data-alt=&quot;Header Compression&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgdFrZ/btq5YvAfV8N/JCw0ssIHEkhPwNU93VJSz1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgdFrZ%2Fbtq5YvAfV8N%2FJCw0ssIHEkhPwNU93VJSz1%2Ftfile.svg&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;150&quot; data-filename=&quot;2.svg&quot; width=&quot;465&quot; height=&quot;391&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Header Compression&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레퍼런스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;url&quot; href=&quot;https://developers.google.com/web/fundamentals/performance/http2/?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.google.com/web/fundamentals/performance/http2/?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;url&quot; href=&quot;https://kinsta.com/learn/what-is-http2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kinsta.com/learn/what-is-http2/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>네트워크</category>
      <category>Domain Sharding</category>
      <category>Header Compression</category>
      <category>HOL Blocking</category>
      <category>HTTP 1.1</category>
      <category>HTTP 1.1 VS HTTP 2.0</category>
      <category>HTTP 2.0</category>
      <category>HTTP Pipelining</category>
      <category>Multiplexed Streams</category>
      <category>Server Push</category>
      <category>Stream Prioritization</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/341</guid>
      <comments>https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP-11-VS-HTTP-20#entry341comment</comments>
      <pubDate>Fri, 28 May 2021 01:38:40 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] 서브도메인과 A Record, CNAME</title>
      <link>https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%84%9C%EB%B8%8C%EB%8F%84%EB%A9%94%EC%9D%B8%EA%B3%BC-A-Record-CNAME</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;서브 도메인이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;서브 도메인&lt;/code&gt; 이라는 단어는 처음 들어봤어도 우리는 이미 익숙하게 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버의 서비스들을 예로 들어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버는 메일, 카페, 블로그 등등 많은 서비스를 하고 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 경우 각각의 url은 아래와 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mail.naver.com&lt;/li&gt;
&lt;li&gt;cafe.naver.com&lt;/li&gt;
&lt;li&gt;blog.naver.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가비아, 후이즈, 고대디 등 웹 호스팅 업체에 서브 도메인을 등록할 때는 CNAME과 A레코드 정보를 함께 입력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘은 각각 무엇이고 어떤 차이가 있는지 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;A Record&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;A Record&lt;/code&gt; 는 DNS에 저장할 때 도메인 주소와 IP 주소를 매핑시키는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인에 대한 요청이 오면 대응되는 IP 주소를 반환합니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NAME&lt;/th&gt;
&lt;th&gt;VALUE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;mail.naver.com&lt;/td&gt;
&lt;td&gt;125.209.230.135&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cafe.naver.com&lt;/td&gt;
&lt;td&gt;210.89.168.66&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;blog.naver.com&lt;/td&gt;
&lt;td&gt;223.130.195.143&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CNAME&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;CNAME&lt;/code&gt; 은 Canonical Name의 약자로 도메인 주소와 도메인 주소를 매핑시키는 방법입니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NAME&lt;/th&gt;
&lt;th&gt;VALUE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bar.example.com&lt;/td&gt;
&lt;td&gt;foo.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foo.example.com&lt;/td&gt;
&lt;td&gt;192.0.2.23&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;bar.example.com&lt;/code&gt; 에 대한 요청이 오면 &lt;code&gt;foo.example.com&lt;/code&gt; 를 반환하고 클라이언트는 다시 &lt;code&gt;foo.example.com&lt;/code&gt; 에 대한 요청을 보내 &lt;code&gt;192.0.2.23&lt;/code&gt; 을 얻습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;A Record VS CNAME&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘의 장단점을 비교해보고 어느 상황에 사용해야 할 지 생각해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;A Record&lt;/code&gt; 는 한 번의 요청으로 IP 주소를 바로 얻을 수 있으니 효율적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 IP 주소가 바뀐다면 바꿔야 할 칼럼이 여러 개가 될 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 서브 도메인이 하나의 IP 주소에 &lt;code&gt;A Record&lt;/code&gt; 방식으로 매핑되어 있다면 전부 바꿔줘야하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 비해 &lt;code&gt;CNAME&lt;/code&gt; 은 IP 주소를 얻기 위해 2번 이상의 요청이 필요하므로 비효율적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 IP 주소가 바뀐다면 하나의 칼럼만 바꿔주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 IP 주소가 자주 바뀌어야 하는 환경이라면 &lt;code&gt;CNAME&lt;/code&gt; 을,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니라면 &lt;code&gt;A Record&lt;/code&gt; 사용을 추천합니다.&lt;/p&gt;</description>
      <category>네트워크</category>
      <category>A Record</category>
      <category>A Record VS CNAME</category>
      <category>CNAME</category>
      <category>DNS</category>
      <category>network</category>
      <category>네트워크</category>
      <category>서브 도메인</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/340</guid>
      <comments>https://ssungkang.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%84%9C%EB%B8%8C%EB%8F%84%EB%A9%94%EC%9D%B8%EA%B3%BC-A-Record-CNAME#entry340comment</comments>
      <pubDate>Thu, 27 May 2021 19:29:20 +0900</pubDate>
    </item>
    <item>
      <title>[WEB] JWT를 어디에 보관해야할까</title>
      <link>https://ssungkang.tistory.com/entry/WEB-JWT%EB%A5%BC-%EC%96%B4%EB%94%94%EC%97%90-%EB%B3%B4%EA%B4%80%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저번 포스팅에서는 JWT에 대해서 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;url&quot; href=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621767824018&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[WEB] Authentication (2) JWT&quot; data-og-description=&quot;저번 포스팅에 이어 이번엔 인증하는 두 번째 방법, JWT에 대해서 알아보겠습니다. [WEB] Authentication (1) 세션과 쿠키 [WEB] Authentication (1) 세션과 쿠키 Authentication 우선 Authentication 이 뭔지부터..&quot; data-og-host=&quot;ssungkang.tistory.com&quot; data-og-source-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT&quot; data-og-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FWThx/hyKiflbKdJ/WlD6cWJSxkf4ZZHJpapm40/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bwKgNE/hyKjLpeuZX/DKQqBWz7gaMoNMXXbUqqrK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/OWnHa/hyKipnNFyY/L567jd9LOxrMiKrBKsv0aK/img.png?width=2334&amp;amp;height=960&amp;amp;face=0_0_2334_960&quot;&gt;&lt;a href=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FWThx/hyKiflbKdJ/WlD6cWJSxkf4ZZHJpapm40/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bwKgNE/hyKjLpeuZX/DKQqBWz7gaMoNMXXbUqqrK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/OWnHa/hyKipnNFyY/L567jd9LOxrMiKrBKsv0aK/img.png?width=2334&amp;amp;height=960&amp;amp;face=0_0_2334_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[WEB] Authentication (2) JWT&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저번 포스팅에 이어 이번엔 인증하는 두 번째 방법, JWT에 대해서 알아보겠습니다. [WEB] Authentication (1) 세션과 쿠키 [WEB] Authentication (1) 세션과 쿠키 Authentication 우선 Authentication 이 뭔지부터..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ssungkang.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JWT를 결국 클라이언트가 보관해야하는데 그 보관을 어디서 할 것인가에 대해 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 웹 어플리케이션을 기준으로 이야기 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Web Storage&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Web Storage&lt;/code&gt; 은 HTML5부터 지원되는 기술로 브라우저에 데이터를 저장할 수 있는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Web Storage&lt;/code&gt; 는 &lt;code&gt;session storage&lt;/code&gt;와 &lt;code&gt;local storage&lt;/code&gt;로 구분됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sessionStorage&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sessionStorage는 각 세션마다 데이터가 개별적으로 저장됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 여러 개의 탭을 실행 중이면 각 탭 별로 따로 데이터가 저장됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 세션이 다르면 다른 세션의 sessionStorage에 접근할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sessionStorage에 데이터를 저장하고 가져오는 방법은 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;sessionStorage.setItem('myCat', 'Tom');
var myCat = sessionStorage.getItem('myCat');
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;localStorage&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localStorage는 브라우저에 반영구적으로 저장됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저를 종료해도 데이터가 유지되며 도메인 기준으로 저장을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A.com에서 B.com에 저장한 데이터를 접근할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localStorage에 데이터를 저장하고 가져오는 방법은 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;localStorage.setItem('myCat', 'Tom');
var myCat = localStorage.getItem('myCat');
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방법 모두 javascript를 통해 쉽게 sotrage에 접근이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 접근할 수 있다는 것은 장점이나 단점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XSS 공격에 취약해지기 때문에 보안 상의 문제가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용량은 5MB로 cookies에 비해 여유롭습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Cookies&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Cookies&lt;/code&gt; 는 예전부터 많이 사용하던 기술로 기본적인 개념은 아래 링크에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;url&quot; href=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621767825069&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[WEB] Authentication (1) 세션과 쿠키&quot; data-og-description=&quot;Authentication 우선 Authentication 이 뭔지부터 알아봅시다. 여러분이 어떤 서비스를 이용할 때, 아이디와 비밀번호를 입력하고 로그인을 한 경험이 있으실 겁니다. 이것이 바로 여러분이 서버로 부터 &quot; data-og-host=&quot;ssungkang.tistory.com&quot; data-og-source-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; data-og-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLZ11Q/hyKjxxJ9m6/s2qSW9aPxIj3K3DvenUrl1/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/ct8f00/hyKjx5Azsa/tCPjwMR2epaiYBW5lP9GM1/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/dusxMm/hyKjKjxPkv/MpmbFaM3OP0vp2ogn06Ms0/img.jpg?width=1052&amp;amp;height=1248&amp;amp;face=267_380_686_838&quot;&gt;&lt;a href=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLZ11Q/hyKjxxJ9m6/s2qSW9aPxIj3K3DvenUrl1/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/ct8f00/hyKjx5Azsa/tCPjwMR2epaiYBW5lP9GM1/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/dusxMm/hyKjKjxPkv/MpmbFaM3OP0vp2ogn06Ms0/img.jpg?width=1052&amp;amp;height=1248&amp;amp;face=267_380_686_838');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[WEB] Authentication (1) 세션과 쿠키&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Authentication 우선 Authentication 이 뭔지부터 알아봅시다. 여러분이 어떤 서비스를 이용할 때, 아이디와 비밀번호를 입력하고 로그인을 한 경험이 있으실 겁니다. 이것이 바로 여러분이 서버로 부터&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ssungkang.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Cookies&lt;/code&gt; 는 용량이 4KB로 &lt;code&gt;Web Storage&lt;/code&gt; 에 비해 매우 작습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;code&gt;Cookies&lt;/code&gt; 는 &lt;code&gt;HttpOnly&lt;/code&gt; 옵션이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 옵션을 통해 자바스크립트를 통한 &lt;code&gt;Cookies&lt;/code&gt; 접근을 막아 XSS 공격을 방지 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;code&gt;Secure&lt;/code&gt; 옵션을 통해 HTTPS로만 쿠키가 통신되도록 하여 보안을 더 높여 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 CSRF 공격에는 취약합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 방법 모두 장단점이 있지만 결국 인증을 위한 JWT를 저장하는데 있어서 가장 중요한 부분은 보안입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Cookies&lt;/code&gt; 에 저장하고 위에서 설명한 여러 옵션을 적용하여 보안을 강화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 CSRF 공격에는 취약하지만 이 역시 CSRF TOKEN을 사용하여 보안을 강화할 수 있으므로 &lt;code&gt;Cookies&lt;/code&gt; 에 저장하는 방법이 더 좋다고 생각합니다.&lt;/p&gt;</description>
      <category>웹프로그래밍/이론</category>
      <category>Cookies</category>
      <category>CSRF</category>
      <category>Httponly</category>
      <category>jwt</category>
      <category>JWT 저장 위치</category>
      <category>local storage</category>
      <category>secure</category>
      <category>session storage</category>
      <category>Web storage</category>
      <category>XSS</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/339</guid>
      <comments>https://ssungkang.tistory.com/entry/WEB-JWT%EB%A5%BC-%EC%96%B4%EB%94%94%EC%97%90-%EB%B3%B4%EA%B4%80%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C#entry339comment</comments>
      <pubDate>Sun, 23 May 2021 20:05:37 +0900</pubDate>
    </item>
    <item>
      <title>[WEB] Authentication (2) JWT</title>
      <link>https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저번 포스팅에 이어 이번엔 인증하는 두 번째 방법, JWT에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot;&gt;[WEB] Authentication (1) 세션과 쿠키&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621264835239&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[WEB] Authentication (1) 세션과 쿠키&quot; data-og-description=&quot;Authentication 우선 Authentication 이 뭔지부터 알아봅시다. 여러분이 어떤 서비스를 이용할 때, 아이디와 비밀번호를 입력하고 로그인을 한 경험이 있으실 겁니다. 이것이 바로 여러분이 서버로 부터 &quot; data-og-host=&quot;ssungkang.tistory.com&quot; data-og-source-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; data-og-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dbt9Dp/hyKeZ2TbLf/3HRkkf4JoIrO7UjUFH0Bv0/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/bnD4Np/hyKe86Bee4/kKa3eosIqFSJnqn2QlgPH0/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/5P3pd/hyKfbPNbSp/NhndtvHrj5eC9me7awWqe0/img.jpg?width=1052&amp;amp;height=1248&amp;amp;face=267_380_686_838&quot;&gt;&lt;a href=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ssungkang.tistory.com/entry/WEB-Authentication-1-%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dbt9Dp/hyKeZ2TbLf/3HRkkf4JoIrO7UjUFH0Bv0/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/bnD4Np/hyKe86Bee4/kKa3eosIqFSJnqn2QlgPH0/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/5P3pd/hyKfbPNbSp/NhndtvHrj5eC9me7awWqe0/img.jpg?width=1052&amp;amp;height=1248&amp;amp;face=267_380_686_838');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[WEB] Authentication (1) 세션과 쿠키&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Authentication 우선 Authentication 이 뭔지부터 알아봅시다. 여러분이 어떤 서비스를 이용할 때, 아이디와 비밀번호를 입력하고 로그인을 한 경험이 있으실 겁니다. 이것이 바로 여러분이 서버로 부터&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ssungkang.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JWT 란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JWT란 Json Web Token의 줄임말로 json 형태의 token입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JWT을 만들기 위해서는 &lt;code&gt;header&lt;/code&gt;, &lt;code&gt;payload&lt;/code&gt;, &lt;code&gt;verify signature&lt;/code&gt; 총 3가지가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 3개를 &lt;code&gt;.&lt;/code&gt; 으로 조합하여 아래와 같은 형태로 만들어집니다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;header.payload.verify_signature
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;header&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;header는 일반적으로 token의 타입과 signature 알고리즘이 포함됩니다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;alg&quot;: &quot;HS256&quot;,
  &quot;typ&quot;: &quot;JWT&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 JSON은 Base64Url로 인코딩 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Signature vs Encryption&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Signature : 비밀 키를 가진 소수만 데이터에 서명할 수 있습니다. 그리고 공개 키를 가진 아무나 서명을 검증할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Encryption : 공개 키를 가진 아무나 데이터를 암호화 할 수 있습니다. 그리고 비밀 키를 가진 소수만 데이터를 복호화하여 확인할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;payload&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;payload는 추가적인 데이터를 넣을 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;minsung&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 자주 쓰이는 항목들은 등록된 클레임으로 사전에 지정되어 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;iss: 토큰 발급자 (issuer)&lt;/li&gt;
&lt;li&gt;sub: 토큰 제목 (subject)&lt;/li&gt;
&lt;li&gt;aud: 토큰 대상자 (audience)&lt;/li&gt;
&lt;li&gt;exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.&lt;/li&gt;
&lt;li&gt;nbf : Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.&lt;/li&gt;
&lt;li&gt;iat : 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;jti : JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 JSON은 Base64Url로 인코딩 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;signing된 JWT는 변조로부터 보호되지만 누구나 읽을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 별도의 암호화가 없다면 payload에 보안 상 중요한 값은 넣지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;verify signature&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;verify signature을 생성하기 위해 인코딩된 header, 인코딩된 payload, secret이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 signing 알고리즘이 &lt;code&gt;HS256&lt;/code&gt; 인 경우에는 아래와 같이 생성됩니다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;HMACSHA256(
  base64UrlEncode(header) + &quot;.&quot; +
  base64UrlEncode(payload),
  secret)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;HS256&lt;/code&gt; 은 대칭키 알고리즘으로서 하나의 키가 비밀 키와 공개 키 역할을 모두 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 서버와 클라이언트의 통신 시, JWT를 사용한다면 서명을 하는 주체와 서명을 검증하는 주체가 모두 서버입니다. 따라서 대칭키 알고리즘을 사용해도 문제가 없을 뿐 아니라 비대칭키 알고리즘에 비해 연산이 간단하여 CPU 사용량도 적습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;verify signature은 메세지가 변조되지 않았음을 확인하는데 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 사이트에서 직접 JWT를 만들어 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;url&quot; href=&quot;https://jwt.io/#debugger-io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jwt.io/#debugger-io&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621264849908&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JWT.IO&quot; data-og-description=&quot;JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.&quot; data-og-host=&quot;jwt.io&quot; data-og-source-url=&quot;https://jwt.io/#debugger-io&quot; data-og-url=&quot;http://jwt.io/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/brq7tJ/hyKe1Gpgm1/vOZ3jQxWkfHXPhA0wSM8KK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bHhgje/hyKe2k0XoV/OmBKoPjuoVlWJUtuwFfB4k/img.png?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://jwt.io/#debugger-io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jwt.io/#debugger-io&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/brq7tJ/hyKe1Gpgm1/vOZ3jQxWkfHXPhA0wSM8KK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bHhgje/hyKe2k0XoV/OmBKoPjuoVlWJUtuwFfB4k/img.png?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JWT.IO&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jwt.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JWT를 이용한 인증&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;371&quot; data-filename=&quot;jwt1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NZvcg/btq49axIH5u/v3uwMXqU9TC3Cf0XnxtNek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NZvcg/btq49axIH5u/v3uwMXqU9TC3Cf0XnxtNek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NZvcg/btq49axIH5u/v3uwMXqU9TC3Cf0XnxtNek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNZvcg%2Fbtq49axIH5u%2Fv3uwMXqU9TC3Cf0XnxtNek%2Fimg.png&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;371&quot; data-filename=&quot;jwt1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트에서 인증서버로 권한을 요청합니다. 다양한 방법이 있겠지만 일반적으로 올바른 아이디와 패스워드를 입력하여 인증을 받을 수 있습니다.&lt;/li&gt;
&lt;li&gt;인증서버에서 JWT를 생성하여 클라이언트에게 반환합니다.&lt;/li&gt;
&lt;li&gt;클라이언트는 JWT를 사용하여 보호된 리소스들에 접근할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JWT의 장단점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증에 필요한 모든 정보를 토큰 자체가 포함하기 때문에 별도의 인증 저장소가 필요 없습니다.&lt;/li&gt;
&lt;li&gt;다른 token들에 비해 크기가 작아 트래픽에 대한 부담이 낮습니다.&lt;/li&gt;
&lt;li&gt;expired 기능을 내장하고 있습니다.&lt;/li&gt;
&lt;li&gt;수평 스케일링에 용이합니다.&lt;/li&gt;
&lt;li&gt;micro service 환경에서 중앙집중식 인증서버에서 벗어나 개별 micro service에서 해결할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JWT를 클라이언트에 저장하여 사용하기 때문에 DB에서 값이 바뀌더라도 JWT에 바로 적용할 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;payload에 데이터가 많아지면 JWT의 크기가 커집니다.&lt;/li&gt;
&lt;li&gt;JWT는 거의 모든 요청에 전송되므로 트래픽 크기에 영향을 미칠 수 있습니다.&lt;/li&gt;
&lt;li&gt;한 번 발급한 JWT는 값을 수정하거나 폐기가 불가능합니다.&lt;/li&gt;
&lt;li&gt;기본적으로 암호화하지 않기 때문에 정보가 노출 될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Refresh Token&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Refresh Token&lt;/code&gt; 은 JWT의 단점들을 극복하기 위해 나온 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JWT 값을 수정과 폐기가 불가능하기 때문에 중간에 탈취당할 경우 보안적인 이슈가 생길 뿐더러 DB 값이 바뀌더라도 갱신할 수 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;code&gt;access token&lt;/code&gt;과 &lt;code&gt;refresh token&lt;/code&gt; , 두 개의 JWT를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;access token은 만료기간을 굉장히 짧게 가져가고, refresh token은 비교적 길게 가져갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이용하여 인증하는 방법을 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 token을 발급받는 과정은 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2334&quot; data-origin-height=&quot;960&quot; data-filename=&quot;jwt2.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwDUn6/btq47w8U6q8/BlirMeQanlCvWkVJEuNdVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwDUn6/btq47w8U6q8/BlirMeQanlCvWkVJEuNdVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwDUn6/btq47w8U6q8/BlirMeQanlCvWkVJEuNdVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwDUn6%2Fbtq47w8U6q8%2FBlirMeQanlCvWkVJEuNdVK%2Fimg.png&quot; data-origin-width=&quot;2334&quot; data-origin-height=&quot;960&quot; data-filename=&quot;jwt2.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 경우에는 위에서 봤던 &lt;code&gt;JWT를 이용한 인증&lt;/code&gt; 과 동일합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 access token이 만료된 경우에는 어떨까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만료된 access token으로 요청을 보낸 후 과정은 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2276&quot; data-origin-height=&quot;622&quot; data-filename=&quot;jwt3.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F43hs/btq5bN9pDqK/ceQzJ4qNRO1oso9DQfcHsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F43hs/btq5bN9pDqK/ceQzJ4qNRO1oso9DQfcHsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F43hs/btq5bN9pDqK/ceQzJ4qNRO1oso9DQfcHsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF43hs%2Fbtq5bN9pDqK%2FceQzJ4qNRO1oso9DQfcHsk%2Fimg.png&quot; data-origin-width=&quot;2276&quot; data-origin-height=&quot;622&quot; data-filename=&quot;jwt3.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹프로그래밍/이론</category>
      <category>Access Token</category>
      <category>header</category>
      <category>jwt</category>
      <category>JWT 단점</category>
      <category>JWT 장점</category>
      <category>JWT 특징</category>
      <category>payload</category>
      <category>Refresh Token</category>
      <category>verify signature</category>
      <category>web</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/338</guid>
      <comments>https://ssungkang.tistory.com/entry/WEB-Authentication-2-JWT#entry338comment</comments>
      <pubDate>Tue, 18 May 2021 00:23:35 +0900</pubDate>
    </item>
    <item>
      <title>[MAC] 개발자를 확인할 수 없기 때문에 열 수 없습니다. 문제 해결</title>
      <link>https://ssungkang.tistory.com/entry/MAC-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%ED%99%95%EC%9D%B8%ED%95%A0-%EC%88%98-%EC%97%86%EA%B8%B0-%EB%95%8C%EB%AC%B8%EC%97%90-%EC%97%B4-%EC%88%98-%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0</link>
      <description>&lt;p&gt;MacOS에서 인터넷에서 다운 받은 파일이 실행되지 않는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;이 경우, 아래와 같은 창이 뜨게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;image-20210501182457478.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;309&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sy1H4/btq4qDHov1K/hUPhZMpCmO3xzeaKUZ3GgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sy1H4/btq4qDHov1K/hUPhZMpCmO3xzeaKUZ3GgK/img.png&quot; data-alt=&quot;안내 팝업 창&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sy1H4/btq4qDHov1K/hUPhZMpCmO3xzeaKUZ3GgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsy1H4%2Fbtq4qDHov1K%2FhUPhZMpCmO3xzeaKUZ3GgK%2Fimg.png&quot; data-filename=&quot;image-20210501182457478.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;309&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;안내 팝업 창&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;애플의 보안정책으로 바이러스를 포함한 App일 수 있기 때문에 위와 같은 설정을 해두었습니다.&lt;/p&gt;
&lt;p&gt;따라서 인터넷에서 다운받은 파일은 새로운 속성이 추가되어 있습니다.&lt;/p&gt;
&lt;p&gt;파일의 속성을 확인하기 위해서는 &lt;code&gt;xattr&lt;/code&gt; 명령어를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;xattr {파일 이름}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위 명령어로 다운 받은 파일의 속성을 확인하면 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;xattr chromedriver\ 2 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;com.apple.macl
com.apple.quarantine
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해당 파일을 실행 못하는 이유는 &lt;code&gt;quarantine&lt;/code&gt; (애플의 격리속성) 때문입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 해당 속성을 삭제해야 합니다.&lt;/p&gt;
&lt;p&gt;파일의 속성을 제거하는 명령어도 역시 &lt;code&gt;xattr&lt;/code&gt; 입니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;xattr -d com.apple.quarantine chromedriver\ 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제 정상적으로 파일이 열리는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MAC</category>
      <category>com.apple.quarantine</category>
      <category>MAC</category>
      <category>MacOS</category>
      <category>xattr</category>
      <category>xattr -d</category>
      <category>개발자를 확인할 수 없기 때문에 열 수 없습니다. 문제 해결</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/337</guid>
      <comments>https://ssungkang.tistory.com/entry/MAC-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%ED%99%95%EC%9D%B8%ED%95%A0-%EC%88%98-%EC%97%86%EA%B8%B0-%EB%95%8C%EB%AC%B8%EC%97%90-%EC%97%B4-%EC%88%98-%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0#entry337comment</comments>
      <pubDate>Sun, 9 May 2021 00:30:43 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA] 08. 유용한 클래스</title>
      <link>https://ssungkang.tistory.com/entry/JAVA-08-%EC%9C%A0%EC%9A%A9%ED%95%9C-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
      <description>&lt;p&gt;java.util 패키지에는 수 많은 클래스가 있지만 그 중에서 많이 쓰는 몇 가지를 알아봅시다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;java.util.Objects 클래스&lt;/h3&gt;
&lt;p&gt;Object 클래스의 보조 클래스로 모든 메서드가 static입니다.&lt;/p&gt;
&lt;p&gt;객체의 비교나 널 체크에 유용합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;isNull(), nonNull()&lt;/h4&gt;
&lt;p&gt;isNull()은 해당 객체가 null인지 판단하여 널이면 true를 아니면 false를 반환합니다.&lt;/p&gt;
&lt;p&gt;nonNull()은 정반대로 동작합니다.&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;static boolean isNull(Object obj)
static boolean nonNull(Object obj)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;requiredNonNull()&lt;/h4&gt;
&lt;p&gt;해당 객체가 널이 아니어야 하는 경우에 사용합니다.&lt;/p&gt;
&lt;p&gt;만일 객체가 null이면 NullPointException을 발생시킵니다.&lt;/p&gt;
&lt;p&gt;두 번째 매개변수로 지정하는 문자열은 예외의 메시지가 됩니다.&lt;/p&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;static &amp;lt;T&amp;gt; T requiredNonNull(T obj)
static &amp;lt;T&amp;gt; T requiredNonNull(T obj, String message)
static &amp;lt;T&amp;gt; T requiredNonNull(T obj, Supplier&amp;lt;String&amp;gt; messageSupplier)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래 예제를 보며 requiredNonNull의 편리함을 살펴봅시다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// requiredNonNull이 없는 경우
void setName(String name){
    if(name == null)
        throw new NullPointException(&quot;name must not be null&quot;);
    this.name = name;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// requiredNonNull이 있는 경우
void setName(String name){
    this.name = Objects.requireNonNull(name, &quot;name must not be null&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;compare()&lt;/h4&gt;
&lt;p&gt;Object클래스에는 두 객체의 등가비교를 위한 equals()만 있고 대소 비교를 위한 메서드가 없습니다.&lt;/p&gt;
&lt;p&gt;따라서 Objects 클래스에 추가되었습니다.&lt;/p&gt;
&lt;p&gt;두 비교 대상이 같으면 0, 크면 양수, 작으면 음수를 반환합니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;static int compare(Object a, Object b, Comparator c)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;equals(), deepEquals()&lt;/h4&gt;
&lt;p&gt;Object 클래스에도 equals()가 있지만 Objects 클래스의 equals()는 null 검사를 해야합니다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;// Object 클래스의 equals()
if (a!=null &amp;amp;&amp;amp; a.equals(b)){
  
}

// Objects 클래스의 equals()
if (Objects.equals(a, b)){
  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;단 내부적으로 아래와 같이 구현되어 있기 때문에 객체가 둘 다 null일 경우에도 null을 반환합니다.&lt;/p&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;public static boolean equals(Object a, Object b){
    return (a==b) || (a!=null &amp;amp;&amp;amp; a.equals(b)); 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;deepEquals()는 객체를 재귀적으로 비교하기 때문에 다차원 배열의 비교도 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String[][] str2D = new String [][] {{&quot;a&quot;, &quot;b&quot;}, {&quot;c&quot;, &quot;d&quot;}};
String[][] str2D2 = new String [][] {{&quot;a&quot;, &quot;b&quot;}, {&quot;c&quot;, &quot;d&quot;}};


System.out.println(Objects.equals(str2D, str2D2));
//false
System.out.println(Objects.deepEquals(str2D, str2D2));
// true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;toString()&lt;/h4&gt;
&lt;p&gt;Object 클래스의 toString()과 동일하지만 내부적으로 null 검사를 합니다.&lt;/p&gt;
&lt;p&gt;null일 경우, 두 번째 인자로 사용할 값을 지정할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;static String toString(Object o)
static String toString(Object o, String nullDefault)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;java.util.Random 클래스&lt;/h3&gt;
&lt;p&gt;난수를 얻기 위해서 Math 클래스와 Random 클래스를 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;Math.random()은 내부적으로 Random 클래스의 인스턴스를 생성해서 사용하는 것이므로 둘 중에서 편리한 것을 사용하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;double randNum = Math.random();
double randNum = new Random().nextDouble();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 언어/Java</category>
      <category>java</category>
      <category>java.util.Objects 클래스</category>
      <category>java.util.Random 클래스</category>
      <category>자바</category>
      <author>ssung.k</author>
      <guid isPermaLink="true">https://ssungkang.tistory.com/336</guid>
      <comments>https://ssungkang.tistory.com/entry/JAVA-08-%EC%9C%A0%EC%9A%A9%ED%95%9C-%ED%81%B4%EB%9E%98%EC%8A%A4#entry336comment</comments>
      <pubDate>Fri, 15 Jan 2021 21:18:18 +0900</pubDate>
    </item>
  </channel>
</rss>