robots 차단과 noindex 전달 경계의 충돌 수정

이 글의 목차 8개 항목
  • 분야: DevOps
  • 기술 스택: TypeScript · robots.txt · X-Robots-Tag
  • 관련 기술: 학습 경로 · 인증 리다이렉트 · 검색엔진 크롤링

문제와 원인

학습 경로는 robots.txt에서 크롤링을 막으면서 페이지 metadata에 noindex를 설정했다. 크롤러가 페이지를 읽기 전에 차단돼 색인 제외 신호에 접근할 수 없었다. 비로그인 학습·관리 경로는 인증으로 리다이렉트했고, 해당 응답에는 X-Robots-Tag가 없어 첫 응답에도 제외 신호를 전달할 필요가 있었다.

수정 전 코드

robots()

disallow: [
  "/learn/",
  "/admin",
  "/api/",
],

proxy.ts — proxy()

return applySecurityHeaders(
  NextResponse.next({ request: { headers: requestHeaders } }),
  host === CANONICAL_HOST && protocol === "https",
  request.headers.get("accept")?.includes("text/html") ?? false,
  policy,
);

수정 후 코드

robots에서 /learn/을 제거하고 관리자·API 차단을 유지했다.

robots()

disallow: [
  "/admin",
  "/api/",
],

proxy.ts — proxy()

proxy가 보안 헤더를 적용한 뒤 즉시 반환하던 응답을 변수로 받아, 학습·관리 경로에 X-Robots-Tag를 추가했다.

const response = applySecurityHeaders(
  NextResponse.next({ request: { headers: requestHeaders } }),
  host === CANONICAL_HOST && protocol === "https",
  request.headers.get("accept")?.includes("text/html") ?? false,
  policy,
);
if (/^\/(?:learn|admin)(?:\/|$)/u.test(request.nextUrl.pathname)) {
  response.headers.set("X-Robots-Tag", "noindex, nofollow");
}
return response;

현재 소스는 isIndexableLearningPath로 공개 이론과 개인 풀이·기록 경로를 나누고, 공개 이론에는 일괄 noindex 적용을 제외한다.

검증 결과

Node.js의 로컬 서버에서 수정 전후 원본 proxy·robots 모듈과 실제 NextRequest·NextResponse를 실행했다. canonical HTTPS·HTML GET, 경로 6개·합성 User-Agent 2종(Googlebot·일반 브라우저)을 조합해 수정본별 12개, 총 24개 요청을 각 1회 적용하고 robots 원문 2개를 비교했다. 결과는 인증 handler 앞의 middleware 통과 응답이다.

경로수정 전 robots / proxy 헤더수정 후 robots / proxy 헤더
/learn/sql/sqld/practice차단 / 없음허용 / noindex, nofollow
/learn/sql/sqlp/mock-exams차단 / 없음허용 / noindex, nofollow
/learn/sql/sqld/records차단 / 없음허용 / noindex, nofollow
/admin차단 / 없음차단 / noindex, nofollow
/api/study차단 / 없음차단 / 없음
/api/auth/google/callback차단 / 없음차단 / 없음
표본 집계수정 전수정 후
학습 경로의 크롤링 허용·noindex 동시 충족0/3경로3/3경로
학습·관리 경로의 proxy noindex 헤더0/4경로4/4경로
robots 차단 경로6/6경로3/6경로
API·callback의 proxy noindex 헤더0/2경로0/2경로
두 User-Agent의 판정동일동일

Swagger UI의 로컬 응답 화면(1,280×720 CSS px·DPR 2)은 전후 robots와 수정 후 학습 proxy를 각각 1회 요청한 결과다. robots 응답은 HTTP 200이며, 학습 proxy는 middleware HTTP 200과 X-Robots-Tag: noindex,nofollow를 표시했다.

수정 전: robots의 learn 차단원본 보기 (새 창)

수정 전: robots의 learn 차단

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.

수정 후: learn 차단 제거·관리자와 API 차단 유지원본 보기 (새 창)

수정 후: learn 차단 제거·관리자와 API 차단 유지

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.

학습 경로를 통과한 proxy 응답에는 X-Robots-Tag: noindex,nofollow가 포함됐다.

학습 proxy의 noindex, nofollow 응답 헤더원본 보기 (새 창)

학습 proxy의 noindex, nofollow 응답 헤더

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.