RSS란?
RSS를 정의해 보면, Really Simple Syndication(정말 간단하게 콘텐츠를 한 곳에서 만들고, 여러 곳에서 자동으로 배포·공유하는)라고 할 수 있습니다.
RSS는 어떤 사이트에 새로운 콘텐츠가 올라왔을 때 각각의 해당 사이트에 방문하지 않고, 한 곳에서 콘텐츠를 이용하는 방법인데요, 쉽게 생각하면, 여러 언론사 사이트를 모두 방문할 필요 없이 다양한 기사를 네이버뉴스 한 곳에서 볼 수 있는 것과 같다고 보면 됩니다.
RSS 예시로 뭐가 있을까?
예시로는 블로그가 있습니다. 블로그는 주로 개인이 운영하다보니 업데이트 주기가 길고, 관심이 가는 블로그가 몇 개부터 심하게는 몇백~몇천 개까지 될 수 있어요. 그런데 이러한 블로그들을 모두 즐겨찾기 해 놓고 일일이 새글이 올라왔는지 확인하기란 너무나도 귀찮은 일이므로, RSS리더 한 곳에서 업데이트된 소식만 받을 수 있는 RSS 기능이 쓰이기 시작한 것입니다.
스마트폰에서 이용하면 더욱 편리한데요, 팟캐스트도 RSS를 이용하여 배포하는 방식입니다. 팟캐스트 제작자는 새로운 에피소드(mp3 파일)를 서버에 업로드하고 RSS 피드 파일에 새 에피소드 정보를 추가합니다. 이 RSS 피드에는: 제목, 설명, mp3 파일 위치(URL), 날짜 등이 담겨있는데 구독자 입장에서는 Apple Podcasts, Spotify 등 팟캐스트 앱에서 팟캐스트를 "구독"하게 되는거죠. 이는 실제로는 그 팟캐스트의 RSS 피드 URL을 등록하는 것인데 앱이 주기적으로 RSS 피드를 확인해서 새 에피소드가 있으면 자동으로 알림이 가는것입니다.
현재 국내외 거의 모든 블로그에서 RSS를 지원하고 있으며, 그 외에 일부 언론사나 커뮤니티 사이트에서도 지원하고 있어요. 하지만 대부분의 언론사는 기사 전문을 제공하지 않는데, 그 이유는 페이지뷰와 그를 통한 광고수의 산정에 좋을 게 없기 때문으로 보입니다 😅
간단하게 정리하자면 RSS 구독은 내가 배포자에게서 긁어오는 것 이라고 할 수 있어요.
RSS 피드 만들기
블로그 구독자들이 새 글을 자동으로 받아볼 수 있게 해주는 기능을 만들어 보겠습니다.
기본 구조
RSS 피드는 XML 형식으로 크게 두가지 정보로 나뉘어요.
- 1.채널 정보 - 블로그 전체에 대한 정보
- 블로그 제목, URL, 설명
- 마지막 업데이트 시간
- 언어 설정 등
- 2.아이템 목록 - 각각의 글 정보
- 글 제목과 링크
- 발행일
- 간단한 설명
- 카테고리/태그
RSS 피드 API - 최근 20개 글들을 XML 형식으로 제공
Next.js의 Route Handler를 사용했습니다. /app/rss.xml/route.ts
파일을 만들면 블로그 도메인/rss.xml
로 접근할 수 있어요.
import { NextResponse } from "next/server";
import { getNotionPosts, getNotionLogs } from "@/lib/notion";
// RSS 피드에 사용될 사이트 기본 정보를 상수로 정의
const SITE_URL = "https://www.hyebin.me";
const SITE_TITLE = "이혜빈의 개발블로그";
const SITE_DESCRIPTION = "개발을 기록하는 개발블로그입니다.";
// XML에서 특수 의미를 가진 문자들(&, <, >, ", ')을 안전한 엔티티로 변환
// 이렇게 하지 않으면 XML 파싱 오류가 발생 가능성이 있음
function escapeXml(text: string): string {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// RSS XML 생성 함수
function generateRssXml(posts: any[]): string {
const rssItems = posts
.filter((post) => post.published && post.slug)
.slice(0, 20)
.map((post) => {
const pubDate = new Date(post.date).toUTCString();
const postUrl = `${SITE_URL}/${post.category}/${post.slug}`;
return `
<item>
<title>${escapeXml(post.title || "Untitled")}</title>
<link>${postUrl}</link>
<guid>${postUrl}</guid>
<description>${escapeXml(post.description || "")}</description>
<pubDate>${pubDate}</pubDate>
<category>${escapeXml(post.category || "post")}</category>
${post.tags?.map((tag: string) => `<category>${escapeXml(tag)}</category>`).join("\n ") || ""}
</item>`;
})
.join("");
return `<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>${escapeXml(SITE_TITLE)}</title>
<link>${SITE_URL}</link>
<description>${escapeXml(SITE_DESCRIPTION)}</description>
<language>ko-KR</language>
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
<atom:link href="${SITE_URL}/rss.xml" rel="self" type="application/rss+xml" />
${rssItems}
</channel>
</rss>`;
}
// 각 글들을 RSS 아이템으로 변환
export async function GET() {
try {
// 일반 포스트와 개발 로그를 모두 RSS에 포함시키기 위해 합침
//Promise.all을 사용한 이유는 getNotionPosts()와 getNotionLogs() 두 함수를 병렬로 실행하기 위함
const [posts, logs] = await Promise.all([
getNotionPosts(),
getNotionLogs()
]);
// 포스트와 로그를 합쳐서 날짜순으로 정렬
const allContent = [...posts, ...logs].sort((a, b) =>
new Date(b.date).getTime() - new Date(a.date).getTime()
);
const rssXml = generateRssXml(allContent);
return new NextResponse(rssXml, {
headers: {
"Content-Type": "application/rss+xml; charset=utf-8",
"Cache-Control": "public, max-age=3600, s-maxage=3600", //브라우저와 CDN에서 1시간(3600초) 동안 캐시
},
});
} catch (error) {
console.error("Error generating RSS feed:", error);
return new NextResponse("Error generating RSS feed", { status: 500 });
}
}
robots.txt - 검색 엔진용 설정 파일 생성
///public/robots.txt
User-agent: * //모든 검색엔진(*)에게 모든 페이지(/) 크롤링을 허용
Allow: /
Sitemap: https://www.hyebin.me/sitemap.xml //sitemap 위치를 알려주는 기본적이고 안전한 설정
- 1.크롤링 가이드라인 제공 - 검색엔진에게 어떤 페이지를 크롤링해도 되는지 알려줌
- 2.sitemap 위치 알림 - 사이트맵이 어디에 있는지 검색엔진에 알려줌
- 3.크롤링 효율성 향상 - 불필요한 페이지 크롤링을 방지해 서버 부하 감소
- 4.SEO 모범 사례 - 검색엔진 최적화의 기본 요소
robots.txt는 없어도 되지만 있으면 좋은 이유는 Google 등 주요 검색엔진이 robots.txt를 먼저 확인하기 때문입니다. sitemap.xml 위치를 명시적으로 알려고 향후 특정 경로를 크롤링에서 제외하고 싶을 때도 유용합니다.
제가 쓰는 리더기는 https://feedly.com/i/my/me 입니다. 찾아본 결과 가장 쉽고 유명하더라구요. 심지어 무료로 이용이 가능해요.
위에서 만들어본 RSS 피드를 바로 추가해보겠습니다:-)
피들리 사이트에 들어가서 Follow Sources 를 누르고 팔로우 하기 원하는 rss 링크를 넣어주세요.

만들어 둔 개발 블로그 RSS가 잘 뜨는것을 확인할 수 있습니다! 이제 팔로우 하면 끝!


이제 원하는 블로그들을 하나씩 추가해서 한눈에 글을 파악할 수 있게 되었습니다!