Thymeleaf SEO 메타 태그를 fragment로 통합해 일관성 확보
목차
Thymeleaf SEO fragment를 새로 만들었다. 사내 서비스의 HTML <head> 메타 정보가 여기저기 흩어져 있어서 한 번에 정리가 필요했던 작업.
왜 SEO fragment를 따로 뺐나
서버사이드 렌더링(SSR) 기반 프로젝트에서 Thymeleaf를 쓰다 보면, 초반엔 각 페이지 템플릿에 <meta> 태그를 그냥 직접 박아버리는 경우가 많다. 페이지 수가 적을 때는 별 문제가 없지만, 페이지가 늘어나기 시작하면 상황이 달라진다.
og:title,og:description,og:image같은 Open Graph 태그가 페이지마다 조금씩 다른 형태로 박혀 있음- canonical URL이 있는 페이지, 없는 페이지가 뒤섞임
<title>태그 포맷이 페이지마다 제각각 (서비스명 | 페이지명vs페이지명 - 서비스명)- robots 메타 태그가 필요한 페이지에만 들어가 있는 게 아니라 아예 빠진 페이지도 존재
팀 입장에서 이건 단순한 코드 스타일 문제가 아니라, 실제로 검색 노출에 직결되는 사안이다. SEO 감사(audit)를 한 번 돌려보면 일관성 없는 메타 정보가 얼마나 많은 경고를 뱉어내는지 바로 확인된다.
fragment 구조와 선택의 이유
backend/src/main/resources/templates/fragments/seo.html — 경로를 보면 기존에 이미 fragments/ 디렉터리가 있었을 가능성이 높다. Thymeleaf의 fragment 방식은 공통 레이아웃 관리에서 표준처럼 쓰이는 패턴이다.
<!-- fragments/seo.html -->
<th:block th:fragment="seo(title, description, canonical, ogImage)">
<title th:text="${title} + ' | 서비스명'">서비스명</title>
<meta name="description" th:content="${description}">
<meta name="robots" content="index, follow">
<link rel="canonical" th:href="${canonical}">
<!-- Open Graph -->
<meta property="og:title" th:content="${title}">
<meta property="og:description" th:content="${description}">
<meta property="og:url" th:content="${canonical}">
<meta property="og:image" th:content="${ogImage}">
<meta property="og:type" content="website">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" th:content="${title}">
<meta name="twitter:description" th:content="${description}">
</th:block>
위처럼 파라미터를 받는 fragment로 설계하면, 호출하는 쪽에서 페이지별 값만 넘겨주면 된다.
<!-- 각 페이지 템플릿에서 -->
<th:block th:replace="~{fragments/seo :: seo(
${pageTitle},
${pageDescription},
${canonicalUrl},
${ogImageUrl}
)}"/>
| 방식 | 장점 | 단점 |
|---|---|---|
| 각 페이지에 직접 작성 | 페이지별 커스터마이징 자유도 높음 | 일관성 유지 어려움, 중복 증가 |
| 공통 layout 파일에 고정 | 관리 포인트 단일화 | 페이지별 동적 값 처리 번거로움 |
| 파라미터 fragment | 일관성 + 동적 값 모두 처리 가능 | 초기 설계 필요 |
결국 파라미터 fragment 방식이 SSR 프로젝트에서 SEO를 관리하는 가장 깔끔한 선택이라고 본다.
팀에 주는 영향과 코드리뷰 포인트
이런 fragment가 생기면 팀원들에게 "이제 새 페이지 만들 때 SEO fragment는 반드시 포함" 이라는 가이드를 함께 전달해야 한다. 코드리뷰에서 내가 주로 확인하는 항목은 이렇다.
canonical값이 하드코딩이 아니라 컨트롤러에서 모델에 담겨 내려오는지og:imagefallback이 있는지 (값이 null일 때 기본 이미지로 떨어지는지)<title>길이가 60자를 넘지 않는 구조인지 (검색엔진 권장 범위)description이 160자 이내로 제한되어 내려오는지
특히 canonical URL은 방심하기 쉬운 지점인데, 쿼리 파라미터가 붙은 URL이 그대로 canonical로 들어가면 중복 페이지 문제가 생긴다. 컨트롤러 레이어에서 정제된 값만 모델에 담도록 팀 내 규칙을 잡는 게 맞다.
fragment 하나 추가로 끝나는 작업처럼 보이지만, 이게 있고 없고의 차이는 나중에 SEO 개선 작업을 할 때 체감된다. 기준점이 없으면 개선 자체를 시작하기가 어렵다.
끝.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.