<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>YuuuuuuYu</title><link>https://4d4cat.com/</link><description>Recent content on YuuuuuuYu</description><generator>Hugo -- 0.147.2</generator><language>ko-KR</language><lastBuildDate>Fri, 01 May 2026 13:40:58 +0900</lastBuildDate><atom:link href="https://4d4cat.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Axios compromised on npm</title><link>https://4d4cat.com/posts/2026/axios-compromised-on-npm/</link><pubDate>Sat, 11 Apr 2026 16:18:00 +0900</pubDate><guid>https://4d4cat.com/posts/2026/axios-compromised-on-npm/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>2026년 3월 30일(현지 시간), 주당 1억 회 이상의 다운로드를 기록하는 가장 인기 있는 HTTP 클라이언트 라이브러리인 Axios의 NPM 계정이 해킹되었다.
요약하면, Axios 관리자 계정을 탈취하고 &lt;code>plain-crypto-js&lt;/code>라는 가짜 의존성이 추가된 &lt;code>axios@1.14.1&lt;/code> 및 &lt;code>axios@0.30.4&lt;/code> 버전을 배포했다.&lt;/p>
&lt;p>자세한 건 아래 사이트에 정리되어 있기 때문에 나는 개발자로서 어떻게 대응해야 할지를 중점적으로 작성하려고 한다.&lt;/p>
&lt;h3 id="타임라인">타임라인&lt;/h3>
&lt;p>&lt;a href="https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan">StepSecurity&lt;/a> &lt;br>
&lt;a href="https://www.skshieldus.com/security-insights/trends/axios-supply-chain-attack-insight-report">SK쉴더스&lt;/a>&lt;/p>
&lt;h2 id="대응-전략">대응 전략&lt;/h2>
&lt;h3 id="1-npm-install-시---ignore-scripts-옵션을-사용">1. npm install 시 &lt;code>--ignore-scripts&lt;/code> 옵션을 사용&lt;/h3>
&lt;p>이번 사태에 핵심 원인이기도 했던 자동 스크립트 실행을 막는 옵션이다. 프로젝트에 따라 사용할 때도 있겠지만, 무지성 업그레이드하는 것도 지양해야 한다.&lt;/p></description></item><item><title>What Happened to Claude? A Timeline of Service Disruptions</title><link>https://4d4cat.com/posts/2026/claude-outage/</link><pubDate>Tue, 03 Mar 2026 23:31:00 +0900</pubDate><guid>https://4d4cat.com/posts/2026/claude-outage/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>최근 Claude가 2월 말부터 시작하여 오늘까지 잔 버그(?) 같은 에러가 계속 발생하고 있다. 무슨 문제길래 해결된 것 같아도 다시 발생하는 것일까?&lt;/p>
&lt;p>시기가 미국-이란 전쟁과 맞물려 있어서 AWS 중동 리전 이슈, 군사 작전에 Claude를 사용하여 트래픽 급증했다는 말도 많이 나오고 있다.&lt;/p>
&lt;h3 id="uptime-over-the-past-90-days">Uptime over the past 90 days&lt;/h3>
&lt;p>&lt;img alt="outage" loading="lazy" src="https://4d4cat.com/images/2026/claude-outage.png">&lt;/p>
&lt;h2 id="claude-status-요약">Claude Status 요약&lt;/h2>
&lt;p>사건 이력을 확인해 봤을 때, 3월 1일에는 특별한 이슈가 없던 것 같다.&lt;/p>
&lt;p>따라서, 3월 1일 전후로 살펴보겠다.&lt;/p>
&lt;h3 id="2월">2월&lt;/h3>
&lt;p>여러 장애가 있었지만 대표적으로 3가지로 요약된다.&lt;/p></description></item><item><title>Cloudflare is down Again: What is the root cause this december?</title><link>https://4d4cat.com/posts/2025/cloudflare-outage-2/</link><pubDate>Fri, 05 Dec 2025 18:01:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/cloudflare-outage-2/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>2025년 11월 18일에 이미 장애가 한 번 났는데, 2주가 좀 지난 오늘 또 장애가 발생했다. 다행히 설정 변경 직후 곧바로 감지가 되어서 장애 발생 후, 약 25분만에 문제가 해결되었다.&lt;/p>
&lt;p>&lt;img alt="outage" loading="lazy" src="https://4d4cat.com/images/2025/cloudflare-outage-2.png">&lt;/p>
&lt;h2 id="장애-원인">장애 원인&lt;/h2>
&lt;p>이번 주 공개된 &lt;em>&lt;strong>React Server Components&lt;/strong>&lt;/em> 관련하여 &lt;em>&lt;strong>WAF의 요청 파싱 방식을 변경&lt;/strong>&lt;/em> 중이었다. 그런데 변경 이후, cloudflare 네트워크 전체적으로 다운되는 현상이 발생했다.&lt;/p>
&lt;blockquote>
&lt;p>Resolved&lt;br>
This incident has been resolved.
A change made to how Cloudflare&amp;rsquo;s Web Application Firewall parses requests caused Cloudflare&amp;rsquo;s network to be unavailable for several minutes this morning. This was not an attack; the change was deployed by our team to help mitigate the industry-wide vulnerability disclosed this week in React Server Components. We will share more information as we have it today. &lt;br>
Dec 05, 2025 - 09:20 UTC&lt;/p></description></item><item><title>쿠팡 3370만 개 넘는 계정 개인정보 유출이라 했지만, 사실은 3천개?</title><link>https://4d4cat.com/posts/2025/coupang-data-breach/</link><pubDate>Sat, 29 Nov 2025 18:14:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/coupang-data-breach/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>2025년 11월 29일 17시 53분경 문자 메시지로 개인정보 노출 통지를 받았다. 솔직히 이런 사건 있을 때마다 나는 운 좋게 대상자가 아니었지만, 이번에는 피해 대상자가 되었다. 문자 메시지와 쿠팡 FAQ 내용으로 현 피해자는 약 4500명으로 인지했다고 하는데, 18시 이후에 나온 뉴스를 통해 피해자가 3370만명이 넘는 것으로 확인됐다.&lt;/p>
&lt;p>쿠팡이 사건을 인지한 날짜는 11월 18일이지만, 유출이 시작한 일자는 6월 24일부터로 추정 중이다.&lt;/p>
&lt;p>이후 국정원과 협력하여 조사를 진행했고, 유출자로부터 새로운 사실, 진술서 등을 받은 즉시 정부에 제출했다고 한다. 여기서 밝혀진 내용이 3300만명의 개인정보가 유출된 것이 아니라 그만큼 접근만 한 것이고, 실제 데이터 저장은 약 3천개만 저장했다고 한다. 물론 이 역시 모두 삭제했다고 한다.&lt;/p></description></item><item><title>Cloudflare outage: What went wrong?</title><link>https://4d4cat.com/posts/2025/cloudflare-outage/</link><pubDate>Tue, 18 Nov 2025 23:31:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/cloudflare-outage/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>AWS 장애 사태가 약 한 달이 되어가는데 Cloudflare에서도 장애가 발생했다. 한국 시간 기준으로 20시 48분경부터 Cloudflare가 적용된 일부 서비스가 간헐적으로 500 에러가 발생했다. &lt;del>현재도 대부분의 서비스가 먹통인데,&lt;/del> 내 블로그도 초반에는 먹통이었지만 지금은 접속이 잘 되고 있다. 4시 28분경에 장애가 해결됐고 관련 내용을 발표했다.&lt;/p>
&lt;h2 id="장애-원인">장애 원인&lt;/h2>
&lt;p>&lt;del>포스팅 작성 시간 기준으로는 아직 명확한 원인이 나오지 않았다. Cloudflare 측은 문제가 발견되어 수정 작업을 진행 중인데, 아마도 대부분의 서비스가 안정화됐을 때 다시 보고해 주지 않을까 싶다.&lt;/del>&lt;/p></description></item><item><title>윈도우 10에서 11로 업그레이드 이후 어느 날 부팅 자체가 멈춘 일</title><link>https://4d4cat.com/posts/2025/uefi-raid-conflict-win11-boot/</link><pubDate>Fri, 31 Oct 2025 20:04:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/uefi-raid-conflict-win11-boot/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>취준생 시절 나는 머신러닝에 관심이 생겨서 GPU가 나름 빵빵한 스펙으로 데스크탑을 구매했다.
지금 생각하면 이해가 안 가지만 왜 SSD를 2개를 샀을까? 그냥 용량 합친 것으로 1개 구매하면 됐을 텐데.
그 당시 RAID를 알게 되고 해결된 줄 알았지만 이게 지금에서야 문제가 될지는 한 달 전까지 몰랐다.&lt;/p>
&lt;h3 id="사건의-시작">사건의 시작&lt;/h3>
&lt;p>2025년 9월에 &lt;code>TPM&lt;/code> 설정 후 윈 11로 업그레이드하고 나서는 큰 문제가 없었는데 &lt;em>&lt;strong>10월이 되고 몇몇 업데이트 이후&lt;/strong>&lt;/em> 부팅이 멈추기 시작했다.
이때는 마침 해당 업데이트 전에 시스템 복원 지점이 생성되어 복구하는 것으로 끝났다.&lt;/p></description></item><item><title>2025 AWS US-East-1 region outage: DynamoDB down</title><link>https://4d4cat.com/posts/2025/inside-the-aws-us-east-1-outage/</link><pubDate>Tue, 21 Oct 2025 06:20:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/inside-the-aws-us-east-1-outage/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Thomas Eccel(구글 Ads 스페셜리스트)의 글을 포함한 외국 저널과 AWS에 Service health 내용을 참고하여 작성했습니다.&lt;/strong>&lt;/em>&lt;/p>&lt;/blockquote>
&lt;p>한국 시간 기준, 2025년 10월 20일 오후 4시 경부터 &lt;code>US-EAST-1&lt;/code> 리전을 사용하는 다수의 서비스에서 장애가 발생&lt;/p>
&lt;p>&lt;strong>원인&lt;/strong>: &lt;em>US-EAST-1 리전의 DynamoDB API 엔드포인트의 DNS&lt;/em>&lt;/p>
&lt;p>&lt;strong>영향&lt;/strong>: IAM, DynamoDB 테이블을 포함한 US-EAST-1 엔드포인트에 의존하는 다른 서비스&lt;/p>
&lt;h2 id="장애-원인">장애 원인&lt;/h2>
&lt;p>해당 리전의 DynamoDB API 엔드포인트의 DNS에서 문제가 발생했다고 하는데 구체적으로 어떤 내용일까?&lt;/p>
&lt;blockquote>
&lt;p>Oct 20 2:01 AM PDT We have identified a potential root cause for error rates for the DynamoDB APIs in the US-EAST-1 Region. Based on our investigation, the issue appears to be related to DNS resolution of the DynamoDB API endpoint in US-EAST-1. We are working on multiple parallel paths to accelerate recovery.&lt;/p></description></item><item><title>퇴사하고 공백기가 1년이 넘은 현재까지의 이야기</title><link>https://4d4cat.com/posts/2025/career-gap-story-one-year-later/</link><pubDate>Mon, 20 Oct 2025 03:04:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/career-gap-story-one-year-later/</guid><description>&lt;h2 id="개요">개요&lt;/h2>
&lt;p>하이 리스크였던 첫 퇴사 이후 지금까지 약 15개월 간의 이야기를 정리해보고자 한다.&lt;/p>
&lt;p>커머스 관련 회사에 약 4년 반동안 다니고 건강 문제를 퇴사하게 되었다. 건강이 악화된 이유는 요약하면 &lt;code>스트레스로 인한 건강 악화&lt;/code>지만 자세한 이야기는 가까운 지인들만 알고 있다.&lt;/p>
&lt;hr>
&lt;p>결론부터 말하면 약 150곳의 서류를 넣었고 이 중에서 50개는 결과를 알려주지 않았다.&lt;/p>
&lt;p>면접은 8번을 봤고, 처우 협의까지 간 곳은 1곳이다.&lt;/p>
&lt;h2 id="24년-7월--9월-휴식기">24년 7월 ~ 9월, 휴식기&lt;/h2>
&lt;h3 id="일단-내-몸-먼저">일단 내 몸 먼저&lt;/h3>
&lt;p>어쨋든 퇴사를 하고나서 마음이 한결 가볍긴 했지만 육체는 아직 후유증이 있었나보다. 그래서 처음 2개월은 생각을 비우고 건강 회복에 집중했다. 안그래도 평소에 이것 저것 잡생각이 많은 편이라 맘 먹고 쉬기만 했다.&lt;/p></description></item><item><title>사차원 주머니 프로젝트 근황 1</title><link>https://4d4cat.com/posts/2025/4d4cat-service1/</link><pubDate>Wed, 20 Aug 2025 04:13:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/4d4cat-service1/</guid><description>&lt;p>🔔 &lt;strong>사이드 프로젝트 근황&lt;/strong>&lt;br>
🔔 &lt;strong>추후 개선 방향&lt;/strong>&lt;/p>
&lt;h2 id="이전-요약">이전 요약&lt;/h2>
&lt;p>사차원 주머니 프로젝트를 처음에는 개발 공부용으로만 생각했지만, 실제 서비스를 운영하는 방식으로 방향을 전환했다. 이전에는 템플릿 엔진(&lt;strong>&lt;code>Thymeleaf&lt;/code>&lt;/strong>)으로 프론트엔드를 구성하고, &lt;strong>&lt;code>소셜 로그인&lt;/code>&lt;/strong> 과 &lt;strong>&lt;code>일별 구글 검색 키워드 순위&lt;/code>&lt;/strong> 기능을 구현했었다.&lt;/p>
&lt;h3 id="작업-내용">&lt;a href="https://4d4cat.com/posts/2024/4d4cat1">작업 내용&lt;/a>&lt;/h3>
&lt;h2 id="개요">개요&lt;/h2>
&lt;p>하지만 이 방식은 백엔드 개발자로서 &lt;strong>&lt;code>API Response&lt;/code>&lt;/strong> 처리에 대한 고민이 부족했고, 실제 배포를 해도 사용자에게 큰 의미가 없는 웹사이트가 되어 방향성을 잃은 상태였다.&lt;/p>
&lt;p>그래서 과감하게 백엔드 개발에만 집중하고 프론트엔드는 AI에게 맡기는 방식으로 구조를 변경했다.&lt;/p></description></item><item><title>Windows에서 WSL 설치하다가 컴퓨터 부팅도 못 할뻔한 후기</title><link>https://4d4cat.com/posts/2025/windows-wsl/</link><pubDate>Thu, 26 Jun 2025 23:30:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/windows-wsl/</guid><description>&lt;p>🔔 &lt;strong>Windows에서 WSL 설치 시 발생할 수 있는 문제&lt;/strong>&lt;/p>
&lt;h2 id="개요">개요&lt;/h2>
&lt;p>요즘 흔히 말하는 &amp;ldquo;&lt;strong>바이브 코딩&lt;/strong>&amp;ldquo;에 관심을 가져서 이것저것 하던 와중, &lt;code>Claude&lt;/code>에서 &lt;strong>Claude Code&lt;/strong>를 발표한 것을 보았다. 커서 AI를 이용한 개발은 봤지만 &lt;strong>Claude Code&lt;/strong>는 기본적으로 &lt;strong>CLI&lt;/strong> 방식이어서 신선했다.&lt;/p>
&lt;p>&lt;strong>IntelliJ&lt;/strong>나 &lt;strong>VSCode&lt;/strong>에 통합하여 사용할 수도 있기 때문에 데스크탑(Windows)에 적용해보려고 WSL을 설치했다. 그런데 문제는 이때부터 시작되었다.&lt;/p>
&lt;h2 id="1-wsl-설치">1. WSL 설치&lt;/h2>
&lt;p>WSL(Windows Subsystem for Linux)는 Windows에서 Linux 환경을 사용할 수 있게 해주는 기능이다. 가상머신 없이도 Windows 안에서 리눅스 환경으로 작업할 수 있다는 정도로 알고 있었다.&lt;/p></description></item><item><title>Jekyll RSS를 생성할 때, jekyll-feed로 적용해보기</title><link>https://4d4cat.com/posts/2025/jekyll-rss/</link><pubDate>Wed, 09 Apr 2025 02:38:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/jekyll-rss/</guid><description>&lt;h3 id="introduction">&lt;strong>Introduction&lt;/strong>&lt;/h3>
&lt;p>The Atom Syndication Format is an XML language used for web feeds. A web feed (also called &amp;rsquo;news feed&amp;rsquo; or &amp;lsquo;RSS feed&amp;rsquo;) is a data format used for providing users with frequently updated content. Content distributors syndicate a web feed, thereby allowing users to subscribe a channel to it. A typical scenario of web-feed use might involve the following: a content provider publishes a feed link on its site which end users can register with an aggregator program (also called a feed reader or a news reader) running on their own machines.&lt;/p></description></item><item><title>Photopic) 여기서 경험한 개발 문화</title><link>https://4d4cat.com/posts/2025/photopic-engineering-culture/</link><pubDate>Sun, 06 Apr 2025 13:52:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/photopic-engineering-culture/</guid><description>&lt;blockquote>
&lt;p>&lt;strong>&lt;a href="https://4d4cat.com/posts/2025/photopic-aws-lambda">이전 포스트&lt;/a> 를 읽고 오시는 것을 추천드립니다.&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>이번 프로젝트를 하면서 가장 좋은 경험 중 하나가 개발 문화였다. 백엔드 개발자로서 같은 백엔드와, 다른 직군들과 소통을 할 때 어떤 용어를 사용하고 협업하는게 이전 직장에서는 경험하지 못했던 새로운 경험이었다.&lt;/p>
&lt;p>이전 직장에서는 개발 용어집은 있었지만 제대로 적용하지 않은 부분이 많았고, 코드 리뷰가 없고 알아서 잘 했겠지 하는 마인드로 테스트는 작업한 사람만 했다. 그래서 나는 중요한 작업의 경우 내가 1차로 테스트 후 PR을 올릴 때, 전체 플로우랑 중요하게 봤으면 하는 부분들을 언급해서 요청했었다.&lt;/p></description></item><item><title>Photopic) AWS Lambda를 왜 써야할까?</title><link>https://4d4cat.com/posts/2025/photopic-aws-lambda/</link><pubDate>Sat, 05 Apr 2025 12:55:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/photopic-aws-lambda/</guid><description>&lt;blockquote>
&lt;p>&lt;strong>&lt;a href="https://4d4cat.com/posts/2025/photopic">이전 포스트&lt;/a> 를 읽고 오시는 것을 추천드립니다.&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>내가 뽀또픽을 진행하면서 맡은 업무 중 이미지 업로드가 있는데, 이 작업을 하면서 왜 Lambda를 쓰게 됐는지 기록하고자 한다.&lt;/p>
&lt;h2 id="초기-설계-시작-">&lt;strong>초기 설계 (시작 ~ 1차 MVP)&lt;/strong>&lt;/h2>
&lt;p>인프라는 AWS 서버를 사용하니 이미지 저장을 위해 S3 스토리지를 이용하고 필요한 부분이 생기면 Lambda도 사용하자는 계획이 있었다. 예시로 추후 리사이징 기능을 추가한다면 메인 서버에서 처리하기보다 람다에 리사이징을 맡기는 것이 트래픽 분산이나 유지보수에 좋다고 판단을 했다.&lt;/p>
&lt;p>하지만 규모가 작은 서비스에서 굳이 Lambda를 쓰지 않아도 충분히 주요 기능을 구현했기 때문에 Lambda는 안쓰는 것으로 결정했다. 또, 1차 MVP에서 이미지 확장자를 jpg(jpeg), png, gif만 허용하기로 결정했기 때문에 람다는 쓰지 않는 방향으로 결정했다.&lt;/p></description></item><item><title>Photopic) 스위프 8기 단기 프로젝트 후기, 뽀또픽</title><link>https://4d4cat.com/posts/2025/photopic/</link><pubDate>Mon, 31 Mar 2025 21:20:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/photopic/</guid><description>&lt;p>🔔 &lt;strong>프로젝트 참여 과정&lt;/strong>&lt;br>
🔔 &lt;strong>프로젝트 소개&lt;/strong>&lt;/p>
&lt;h2 id="참여-계기">&lt;strong>참여 계기&lt;/strong>&lt;/h2>
&lt;p>이전 직장에서 레거시한 경험만 있다 보니 스킬업을 하기 위해, 내 레벨이 시장에서 어느 정도인지 측정하기 위해 참가했다. 스위프 8기 프로그램은 서류접수와 참가비만 있으면 됐다. 팀 빌딩 때 프로필을 보니 대부분이 20대이며, 취준생과 신입들이 많았다.&lt;/p>
&lt;p>프로젝트 기간은 팀 빌딩기간부터 마지막 발표하는 날까지 1/15 ~ 3/15, 두달간 진행했다.&lt;/p>
&lt;h2 id="프로젝트와-팀원">&lt;strong>프로젝트와 팀원&lt;/strong>&lt;/h2>
&lt;p>우리 팀은 기획1, 디자이너1, 프론트2, 백엔드2(나 포함)로 구성했다. 스위프에서 팀 빌딩을 위해 각 프로필을 노션 페이지를 공유해줬는데 거기서 지금의 팀원들을 만났다. 프로젝트 아이디어는 여러 의견이 있었지만 &amp;ldquo;SNS에 어떤 사진을 올리는게 좋을까?&amp;ldquo;라는 의문을 해결하기 위해 사진을 투표하고 공유할 수 있는 &amp;ldquo;뽀또픽&amp;quot;이라는 서비스를 만들었다.&lt;/p></description></item><item><title>springframework.http.ResponseEntity</title><link>https://4d4cat.com/posts/2025/response-entity/</link><pubDate>Fri, 24 Jan 2025 11:05:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/response-entity/</guid><description>&lt;p>🔔 &lt;strong>ResponseEntity 개요&lt;/strong>&lt;br>
🔔 &lt;strong>다른 방법과 비교&lt;/strong>&lt;/p>
&lt;h2 id="what-why">&lt;strong>What? Why?&lt;/strong>&lt;/h2>
&lt;p>스프링 3 버전부터 도입되었으며, 스프링 MVC에서 HTTP 응답을 다루는 주요 클래스 중 하나이다. HTTP 응답의 전체 내용을 제어할 수 있도록 해주며, 이를 통해 다음과 같은 요소들을 설정할 수 있다.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>상태 코드 (HTTP Status Code)&lt;br>
: 200 OK, 404 Not Found, 500 Internal Server Error 등&lt;/p>
&lt;/li>
&lt;li>
&lt;p>헤더 (Headers) &lt;br>
: 응답 헤더에 특정 값을 추가/수정&lt;/p>
&lt;/li>
&lt;li>
&lt;p>본문 (Body)&lt;br>
: 실제로 클라이언트에게 전달될 데이터&lt;/p>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@GetMapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;/example&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ResponseEntity&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">getExample&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;Hello, World!&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">HttpHeaders&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">HttpHeaders&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Custom-Header&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;CustomValue&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ResponseEntity&lt;/span>&lt;span class="o">&amp;lt;&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">HttpStatus&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">OK&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="responsebody">&lt;strong>@ResponseBody&lt;/strong>&lt;/h3>
&lt;p>객체를 직렬화하여 반환하는 어노테이션으로, 이것만 사용할 경우 헤더를 유연하게 설정할 수 없다.&lt;br>
&lt;code>@ResopnseStatus&lt;/code>를 사용하여 헤더를 설정할 수 있지만, 어노테이션을 별도로 추가해야하는 단점이 있다.&lt;/p></description></item><item><title>4D4cat) 이 어노테이션은 왜 쓰는걸까?</title><link>https://4d4cat.com/posts/2025/4d4cat-etc1/</link><pubDate>Thu, 23 Jan 2025 13:33:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/4d4cat-etc1/</guid><description>&lt;p>🔔 &lt;strong>어노테이션 종류와 용도&lt;/strong>&lt;/p>
&lt;h2 id="requiredargsconstructor">&lt;strong>RequiredArgsConstructor&lt;/strong>&lt;/h2>
&lt;p>&lt;code>Lombok&lt;/code> 라이브러리에서 제공하는 어노테이션으로, 클래스 내의 &lt;code>final&lt;/code> 필드나 &lt;code>@NonNull&lt;/code> 어노테이션이 붙은 필드들을 초기화하는 생성자를 자동으로 생성해준다. 보일러 플레이트 코드를 줄여준다는 것에 이점이 있다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Service&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nd">@RequiredArgsConstructor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">UserService&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">final&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">UserRepository&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">userRepository&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">final&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">EmailService&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">emailService&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Lombok이 아래와 같은 생성자를 자동으로 생성해줍니다.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// public UserService(UserRepository userRepository, EmailService emailService) {&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// this.userRepository = userRepository;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// this.emailService = emailService;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// }&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 서비스 로직...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="autowired와-차이점">&lt;strong>Autowired와 차이점&lt;/strong>&lt;/h3>
&lt;p>실제로 기능은 동일하지만, 코드량의 차이가 있다.&lt;/p></description></item><item><title>OAuth2 Deepdive</title><link>https://4d4cat.com/posts/2025/oauth2-deepdive/</link><pubDate>Sat, 18 Jan 2025 11:48:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/oauth2-deepdive/</guid><description>&lt;p>🔔 &lt;strong>Oauth2 적용 전&lt;/strong>&lt;br>
🔔 &lt;strong>Oauth2 실습&lt;/strong>&lt;/p>
&lt;h2 id="개요">&lt;strong>개요&lt;/strong>&lt;/h2>
&lt;p>최근 개인 프로젝트에서 네이버 로그인을 위해 필요한 부분을 설정하고 로직을 구현했다. 개발 가이드에 맞게 각 단계별로 진행을 했으나&amp;hellip;&lt;/p>
&lt;p>아무리 봐도 &lt;em>&lt;strong>과정 하나 하나를 내 손으로 직접 구현하는게 맞는건가?&lt;/strong>&lt;/em> 라는 의문을 시작으로 좀 더 효율적으로 구현하는 방법을 찾아봤고, 그렇게 &lt;code>Oauth 2.0&lt;/code>으로 로그인하는 방식을 찾게 되었다.&lt;/p>
&lt;h2 id="oauth2-적용-전">&lt;strong>Oauth2 적용 전&lt;/strong>&lt;/h2>
&lt;p>코드 스타일을 떠나서 지금 와서 보니 마치 &lt;code>Oauth 1.0&lt;/code>처럼 구현을 하고 있었다. 나 또한, 각 플로우마다 하드 코딩은 줄이고 변수나 함수를 재활용하기 위해, 보안 요소를 생각하면서 구현했었다.&lt;/p></description></item><item><title>OAuth2</title><link>https://4d4cat.com/posts/2025/oauth2/</link><pubDate>Fri, 17 Jan 2025 17:23:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/oauth2/</guid><description>&lt;p>🔔 &lt;strong>Oauth2? 그럼 Oauth1도?&lt;/strong>&lt;br>
🔔 &lt;strong>Oauth2 동작 과정&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>RFC6749(Oauth 2.0) 문서를 토대로 요약하여 정리한 글이니, 자세한 내용은 &lt;a href="https://datatracker.ietf.org/doc/html/rfc6749">해당 문서&lt;/a>를 참고해주시기 바랍니다.&lt;/p>&lt;/blockquote>
&lt;h2 id="what-why">&lt;strong>What? Why?&lt;/strong>&lt;/h2>
&lt;p>&lt;em>인증(authentication)&lt;/em> 이 아닌 &lt;code>인가(authorization)&lt;/code>에 초점을 맞추며, 리소스 소유자가 클라이언트에게 자신의 리소스에 대한 제한적 접근 권한을 부여할 수 있도록 하는 프레임워크&lt;/p>
&lt;h3 id="역할">&lt;strong>역할&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Resource Owner&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>보호된 리소스(Protected Resource)의 실제 소유자 혹은 주체&lt;/li>
&lt;li>ex) 사용자의 계정, 사용자 데이터&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Resource Server&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>보호된 리소스를 호스팅(저장 및 관리)하고 있는 서버&lt;/li>
&lt;li>클라이언트가 제공하는 액세스 토큰을 검증하고, 유효한 토큰이면 리소스 접근을 허용&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Client&lt;/strong>&lt;/p></description></item><item><title>HttpClient Deepdive</title><link>https://4d4cat.com/posts/2025/httpclient-deepdive/</link><pubDate>Sun, 12 Jan 2025 17:37:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/httpclient-deepdive/</guid><description>&lt;p>🔔 &lt;strong>BodyPublisher, BodyHandler 역할&lt;/strong>&lt;br>
🔔 &lt;strong>HttpClient 실습&lt;/strong>&lt;/p>
&lt;h2 id="bodypublisher-bodyhandler">&lt;strong>BodyPublisher? BodyHandler?&lt;/strong>&lt;/h2>
&lt;p>&lt;code>BodyPublisher&lt;/code>와 &lt;code>BodyHandlers&lt;/code>는 요청과 응답의 본문을 처리하는 데 있어 상호 보완적인 역할을 한다. &lt;code>BodyPublisher&lt;/code>는 클라이언트가 서버로 전송할 데이터를 정의하고, &lt;code>BodyHandlers&lt;/code>는 서버로부터 받은 데이터를 어떻게 처리할지를 정의한다. 이 두 구성 요소를 적절히 활용하면, HTTP 통신을 더욱 유연하고 효율적으로 구현할 수 있다.&lt;/p>
&lt;h3 id="bodypublisher">&lt;strong>BodyPublisher&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>HTTP 요청의 본문을 제공&lt;/li>
&lt;li>데이터를 전송할 때 어떻게 제공할지 정의
&lt;ul>
&lt;li>&lt;code>BodyPublishers.ofString(String)&lt;/code>: 문자열 데이터&lt;/li>
&lt;li>&lt;code>BodyPublishers.ofByteArray(byte[])&lt;/code>: 바이트 배열 데이터&lt;/li>
&lt;li>&lt;code>BodyPublishers.ofFile(Path)&lt;/code>: 파일 데이터&lt;/li>
&lt;li>&lt;code>BodyPublishers.ofInputStream(Supplier&amp;lt;InputStream&amp;gt;)&lt;/code>: 동적으로 생성되는 입력 스트림&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="bodyhandler">&lt;strong>BodyHandler&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>HTTP 응답의 본문을 처리하는 방법을 정의&lt;/li>
&lt;li>서버로부터 받은 응답 데이터를 어떻게 처리할지 정의
&lt;ul>
&lt;li>&lt;code>BodyHandlers.ofString()&lt;/code>: 문자열 데이터&lt;/li>
&lt;li>&lt;code>BodyHandlers.ofByteArray()&lt;/code>: 바이트 배열 데이터&lt;/li>
&lt;li>&lt;code>BodyHandlers.ofFile(Path)&lt;/code>: 파일 데이터&lt;/li>
&lt;li>&lt;code>BodyHandlers.ofInputStream()&lt;/code>: &lt;code>InputStream&lt;/code>으로 데이터 제공&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>HttpResponse.BodyHandler 클래스는 BodyHandler를 생성하기 위한 여러 가지 편리한 정적 팩토리 메서드를 제공한다. 이들 중 다수는 응답 바이트가 완전히 수신될 때까지 메모리에 축적되며, 그 후 응답 바이트는 상위 수준의 Java 유형(ofString, ofByteArray 등)으로 변환된다.&lt;/p></description></item><item><title>java.net.http.HttpClient</title><link>https://4d4cat.com/posts/2025/httpclient/</link><pubDate>Fri, 10 Jan 2025 16:43:00 +0900</pubDate><guid>https://4d4cat.com/posts/2025/httpclient/</guid><description>&lt;p>🔔 &lt;strong>HttpClient 개요&lt;/strong>&lt;br>
🔔 &lt;strong>HttpClient 개선 과정&lt;/strong>&lt;br>
🔔 &lt;strong>다른 라이브러리 비교&lt;/strong>&lt;/p>
&lt;h2 id="what-why">&lt;strong>What? Why?&lt;/strong>&lt;/h2>
&lt;p>자바에서 HTTP 요청을 생성하고, 서버와 통신하며, 응답을 처리하기 위한 API &lt;br>
Java 11에서 표준 라이브러리로 도입되었으며, 이전의 &lt;code>HttpURLConnection&lt;/code>보다 사용하기 쉽고 기능이 풍부하다.&lt;/p>
&lt;ul>
&lt;li>빌더 패턴 도입: &lt;code>HttpRequest&lt;/code>.newBuilder()&lt;/li>
&lt;li>역할 분리: &lt;code>HttpClient&lt;/code>, &lt;code>HttpRequest&lt;/code>, &lt;code>HttpResponse&lt;/code>&lt;/li>
&lt;li>비동기 처리 지원: &lt;code>HttpClient&lt;/code>.sendAsync()&lt;/li>
&lt;/ul>
&lt;h3 id="주요-클래스">&lt;strong>주요 클래스&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>&lt;code>HttpClient&lt;/code>: HTTP 요청을 보내기 위한 클라이언트 객체를 생성&lt;/li>
&lt;li>&lt;code>HttpRequest&lt;/code>: HTTP 요청의 세부 사항(URI, 메서드, 헤더 등)&lt;/li>
&lt;li>&lt;code>HttpResponse&lt;/code>: 서버로부터 받은 HTTP 응답&lt;/li>
&lt;/ul>
&lt;h3 id="주요-메서드">&lt;strong>주요 메서드&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>&lt;code>HttpClient&lt;/code>.newHttpClient()&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>기본 설정을 사용한 HttpClient 인스턴스를 생성 &lt;br>
- 요청(GET), 프로토콜(HTTP/2), 리다이렉트(NEVER), SSL(Default)&lt;/p></description></item></channel></rss>