쓰레기 쿼리 파라미터 제거 방법 | 중복 URL 색인과 301 리다이렉트 정리

서치콘솔의 페이지 리포트를 보다가 제가 만든 적 없는 주소들이 계속 잡히는 것을 봤습니다. 게시글은 하나인데 주소 뒤에 이상한 파라미터가 붙은 URL이 여러 개 생겨 있었습니다.

처음에는 검색엔진이 알아서 정리할 거라고 생각했습니다. 하지만 시간이 지나도 줄지 않았고, 오히려 비슷한 주소가 더 쌓였습니다. 결국 문제는 외부에서 붙은 파라미터만이 아니라, 오래된 사이트 구조와 버튼 방식이 중복 URL을 계속 만들고 있다는 점이었습니다.

이 글은 쿼리 파라미터를 무조건 지우는 방법을 설명하는 글이 아닙니다. ckattempt, fbclid, utm, x=0&y=0처럼 필요 없는 값이 붙은 URL을 색인에서 정리하면서, 어떤 파라미터는 지우고 어떤 파라미터는 남겨야 하는지 정리한 글입니다.

불필요한 쿼리 파라미터를 제거하고 정규 URL로 301 이동하는 PHP 코드

서치콘솔에 쌓인 이상한 주소들

서치콘솔에서 발견한 주소는 이런 형태였습니다.

/board/856?ckattempt=1
/board/856?fbclid=IwAR3xK...
/board/856?utm_source=kakao&utm_medium=share
/board/856?x=12&y=8
/board/856?
/board/856?123

주소는 다르지만 내용은 모두 같은 게시글이었습니다. 검색엔진 입장에서는 같은 글이 여러 URL로 열리는 구조입니다.

이런 주소가 많아지면 문제가 생깁니다.

  • 같은 본문이 여러 URL로 나뉘어 잡힘
  • 크롤러가 불필요한 주소를 반복해서 방문
  • 정규 URL 판단이 늦어짐
  • 서치콘솔의 중복 페이지 보고가 늘어남
  • 중요한 페이지 크롤링이 뒤로 밀릴 수 있음

특히 작은 사이트에서는 크롤링 기회가 넉넉하지 않습니다. 의미 없는 파라미터 URL이 많아지면 실제로 색인시키고 싶은 글이 늦게 반영될 수 있습니다.

파라미터가 붙는 흔한 경로

이상한 파라미터가 전부 공격이나 오류는 아니었습니다. 출처가 있는 값도 많았습니다.

파라미터주요 출처처리 방향
ckattempt쿠키 확인, 보안 플러그인, 리다이렉트 과정대부분 제거
fbclid페이스북 공유 링크정규 URL로 정리
utm_*광고, 메일, SNS 유입 추적통계 목적이면 보존 검토
x, y이미지 버튼 클릭 좌표버튼 방식 수정
임의 문자열봇, 스크래퍼, 잘못된 외부 링크제거

여기서 특히 오래 헤맨 것은 x, y 값이었습니다. 검색 버튼을 <input type="image">로 만들면 브라우저가 클릭한 좌표를 자동으로 전송합니다.

<input type="image" src="/img/search.gif" alt="검색">

이 버튼을 누르면 검색어 외에 x=12&y=8 같은 값이 붙을 수 있습니다. 클릭 위치가 매번 달라지기 때문에 중복 URL이 계속 생기는 구조가 됩니다.

이미지 버튼부터 일반 버튼으로 교체

먼저 중복 URL을 계속 만들어내는 원인을 줄였습니다. 검색 버튼이나 이동 버튼에 이미지 입력을 쓰고 있다면 일반 버튼으로 바꾸는 편이 좋습니다.

<!-- 좌표 파라미터가 붙을 수 있는 방식 -->
<input type="image" src="/img/search.gif" alt="검색">

아래처럼 바꾸면 클릭 좌표가 쿼리스트링으로 붙지 않습니다.

<!-- 좌표 파라미터 없이 검색 기능만 실행 -->
<button type="submit" aria-label="검색">
    <img src="/img/search.gif" alt="">
</button>

이미지는 장식으로 처리하고, 버튼의 기능은 aria-label="검색"으로 전달했습니다. 이렇게 하면 접근성도 좋아지고, x, y 같은 불필요한 파라미터도 줄일 수 있습니다.

허용 목록으로 남길 값부터 결정

파라미터 정리는 제거 목록보다 허용 목록으로 접근하는 것이 안전했습니다. 무조건 지우면 검색어, 페이징, 카테고리 값까지 사라질 수 있기 때문입니다.

<?php
$allowed = ['id', 'menu', 'post', 'start', 'keyword', 'category'];

if (!empty($_SERVER['QUERY_STRING'])) {
    parse_str($_SERVER['QUERY_STRING'], $params);
    $extra = array_diff(array_keys($params), $allowed);

    if (!empty($extra)) {
        $keep  = array_intersect_key($params, array_flip($allowed));
        $clean = strtok($_SERVER['REQUEST_URI'], '?');

        if (!empty($keep)) {
            $clean .= '?' . http_build_query($keep);
        }

        header('Location: ' . $clean, true, 301);
        exit;
    }
}
?>

이 코드는 허용되지 않은 파라미터가 있을 때만 301 리다이렉트를 실행합니다. 그리고 start, keyword, category처럼 실제 기능에 필요한 값은 남겨둡니다.

예를 들면 아래처럼 정리됩니다.

/board/856?ckattempt=1              → /board/856
/board/856?fbclid=abc               → /board/856
/board/856?keyword=test&x=12&y=8    → /board/856?keyword=test
/board/856?start=20&category=notice → 유지

핵심은 “전부 지우기”가 아니라 “필요한 값만 남기기”입니다.

utm 파라미터는 바로 지우기 전에 확인

utm_source, utm_medium, utm_campaign은 조금 다르게 봐야 합니다. 광고나 SNS 유입 분석에 쓰고 있다면 301로 바로 제거했을 때 통계가 끊길 수 있습니다.

?utm_source=kakao&utm_medium=share&utm_campaign=event

이 값이 실제 분석에 필요 없다면 정규 URL로 보내도 됩니다. 하지만 캠페인 성과를 보고 있다면 일정 기간은 허용하거나, canonical로만 정리하는 방식도 검토해야 합니다.

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

저는 운영 중인 광고가 없는 페이지는 301로 정리하고, 유입 분석이 필요한 링크는 바로 제거하지 않는 식으로 나눴습니다. SEO 정리만 보고 통계 목적을 지워버리면 나중에 유입 경로를 확인할 수 없습니다.

canonical로 정규 주소 다시 표시

301 리다이렉트를 넣었더라도 canonical은 같이 출력했습니다. 리다이렉트가 적용되지 않는 예외 상황이나 외부 캐시를 대비하기 위해서입니다.

<?php
$canonical = 'https://example.com/' . $siteId . '/board/' . (int)$boardNo;

echo '<link rel="canonical" href="'
    . htmlspecialchars($canonical, ENT_QUOTES, 'UTF-8')
    . '">' . "\n";
?>

canonical은 검색엔진에게 “이 페이지의 대표 주소는 이것”이라고 알려주는 신호입니다. 301만큼 강한 이동 신호는 아니지만, 중복 URL 정리에는 같이 쓰는 것이 좋았습니다.

단, canonical도 페이지마다 정확해야 합니다. 모든 글이 홈으로 canonical을 보내거나, 목록과 상세가 같은 canonical을 쓰면 더 큰 문제가 됩니다.

robots.txt로 막지 않은 이유

처음에는 이런 생각도 했습니다.

User-agent: *
Disallow: /*?

쿼리스트링이 붙은 URL을 전부 막으면 크롤링 낭비가 줄어들 것처럼 보입니다. 하지만 이미 색인된 파라미터 URL을 정리해야 하는 상황에서는 좋은 방법이 아닙니다.

검색엔진이 들어오지 못하면 301도 확인할 수 없고, canonical도 읽을 수 없습니다. 그러면 색인에서 빠지는 속도가 오히려 느려질 수 있습니다.

이미 잡힌 URL을 정리하려면 크롤러가 한 번은 들어와서 “정규 주소로 이동한다”는 신호를 봐야 합니다. 그래서 robots.txt로 먼저 막는 대신 301과 canonical로 정리했습니다.

적용 후 확인한 항목

규칙을 넣은 뒤에는 서치콘솔만 기다리지 않고 실제 응답을 먼저 확인했습니다.

curl -I "https://example.com/board/856?ckattempt=1"
curl -I "https://example.com/board/856?fbclid=test"
curl -I "https://example.com/board/856?keyword=test&x=12&y=8"

원하는 결과는 이렇습니다.

/board/856?ckattempt=1           → 301 → /board/856
/board/856?fbclid=test           → 301 → /board/856
/board/856?keyword=test&x=12&y=8 → 301 → /board/856?keyword=test

브라우저에서도 검색, 페이징, 카테고리 이동을 직접 눌러봤습니다. 특히 검색어가 사라지지 않는지 반드시 확인했습니다. 파라미터 정리 규칙은 SEO에는 좋아 보여도 검색 기능을 망가뜨릴 수 있기 때문입니다.

서치콘솔에서 본 변화

반영은 바로 되지 않았습니다. 며칠에서 몇 주 단위로 서서히 바뀌었습니다.

확인한 곳은 주로 두 군데였습니다.

  1. 페이지 색인 리포트
  2. URL 검사 도구

중복 URL이 바로 사라지는 것이 아니라, 먼저 “대체 페이지”나 “사용자가 선택한 표준 URL과 다른 표준 URL” 같은 상태로 이동하는 경우가 있었습니다.

중요한 것은 숫자가 하루 만에 줄지 않는다고 규칙을 계속 바꾸지 않는 것입니다. 저는 예전에 조급하게 규칙을 바꾸다가 검색 파라미터까지 지워서 검색 기능을 망가뜨린 적이 있었습니다.

쓰레기 파라미터 점검 체크리스트

중복 URL은 만드는 원인부터 줄이기

ckattempt, fbclid, 임의 문자열처럼 외부에서 붙는 값도 있지만, 생각보다 많은 파라미터는 사이트 안에서 만들어지고 있었습니다. 특히 이미지 버튼의 x, y 좌표는 직접 보기 전까지 원인을 알기 어려웠습니다.

이미 색인된 URL은 301과 canonical로 정리해야 합니다. 하지만 그 전에 새 중복 URL을 계속 만들어내는 폼, 버튼, 링크부터 줄여야 합니다.

제가 얻은 기준은 단순합니다. 필요한 파라미터는 남기고, 필요 없는 파라미터는 정규 주소로 모읍니다. 그리고 색인 정리 중에는 robots.txt로 먼저 막지 않습니다. 크롤러가 이동 신호와 canonical을 확인할 수 있어야 중복 URL이 제대로 줄어듭니다.

댓글 남기기