개발 기록/SEO

Google Search Console - 색인 생성 불가능 문제 (w.Next.js)

시유후 2025. 10. 17. 11:09

문제 상황

Google Search Console에서 "페이지 색인이 생성되지 않음: 중복 페이지, Google에서 사용자와 다른 표준을 선택함" 오류 발생

  • 사용자가 원하는 표준 URL: https://example.com/en/blog/...
  • Google이 선택한 표준 URL: https://www.example.com/posts/...

원인 분석

1. Canonical 태그 문제

문제점: 모든 페이지의 canonical 태그가 메인 페이지를 가리키고 있음

<!-- 잘못된 예시 -->
<link rel="canonical" href="https://example.com" />

원인: 각 페이지의 고유한 URL을 canonical로 지정하지 않아 Google이 혼란스러워함

2. 메타 태그 불일치 문제

문제점: 페이지마다 메타 태그 작성 방식이 달라 일관성 없음

<!-- 페이지 A -->
<meta property="og:url" content="https://example.com/posts/..." />

<!-- 페이지 B -->
<meta property="og:url" content="https://www.example.com/blog/..." />

<!-- 페이지 C -->
<meta property="og:url" content="https://example.com/en/articles/..." />

원인:

  • 수동으로 작성한 메타 태그들이 서로 다른 URL 형식 사용
  • OG 태그, Twitter 카드, 일반 메타 태그가 제각각 다른 정보 포함

3. 307 임시 리다이렉트 문제

문제점: 리다이렉트가 307 (Temporary Redirect)로 처리되고 있음

curl -IL https://www.example.com/posts/article-title
HTTP/2 307  # 임시 리다이렉트
location: /en/blog/article-title

원인:

  • Next.js의 NextResponse.redirect()는 기본적으로 307 상태 코드 사용
  • 307은 임시 리다이렉트로, Google이 "나중에 원래 URL로 돌아갈 수 있다"고 판단
  • 영구적인 URL 이동임을 Google에 알리지 못함

문제 해결

1. Canonical 태그 수정

Before:

<link rel="canonical" href="https://example.com" />

After:

<link rel="canonical" href="https://example.com/en/blog/solving-duplicate-content-issues" />

적용 방법:

  • 각 페이지의 고유한 정규화된 URL을 canonical로 지정
  • 동적으로 현재 페이지 URL을 삽입하도록 수정

2. 메타 태그 통합 및 표준화

Before: 페이지마다 다른 방식으로 메타 태그 작성

// 수동 작성
<meta property="og:title" content="..." />
<meta name="twitter:title" content="..." />
<title>...</title>

After: Next.js의 generateMetadata API 사용

// app/[locale]/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
  const canonicalUrl = `https://example.com/en/blog/${params.slug}`

  return {
    title: 'Page Title',
    description: 'Page Description',
    alternates: {
      canonical: canonicalUrl,
    },
    openGraph: {
      url: canonicalUrl,
      title: 'Page Title',
      description: 'Page Description',
    },
    twitter: {
      card: 'summary_large_image',
      title: 'Page Title',
      description: 'Page Description',
    },
  }
}

장점:

  • 모든 메타 태그가 동일한 정보 사용
  • 자동으로 정규화된 URL 생성
  • 유지보수 용이

3. 301 영구 리다이렉트 적용

Before: middleware.ts

export function middleware(request: NextRequest) {
  const url = request.nextUrl.clone()

  if (url.pathname.startsWith('/posts/')) {
    url.pathname = url.pathname.replace('/posts/', '/en/blog/')
    return NextResponse.redirect(url)  // 기본값 307
  }
}

After: 301 상태 코드 명시

export function middleware(request: NextRequest) {
  const url = request.nextUrl.clone()

  if (url.pathname.startsWith('/posts/')) {
    url.pathname = url.pathname.replace('/posts/', '/en/blog/')
    return NextResponse.redirect(url, { status: 301 })  // 영구 리다이렉트
  }
}

검증 : curl로 리다이렉트 확인

curl -IL https://example.com/blog

// HTTP/2 301 ... 으로 리다이렉트 확인