문제

Chrome이 ERR_SPDY_PROTOCOL_ERROR를 내며 페이지를 못 엽니다. 같은 사이트가 Firefox에서는, 휴대폰에서는, 시크릿 창에서는 되는데 — 이 Chrome에서, 이 페이지만 계속 죽습니다. 게다가 오류는 Chrome이 10년 전에 지원을 끊은 프로토콜, SPDY의 이름을 부르니, 마치 유령이 보낸 메시지처럼 읽힙니다.

유령이 아닙니다. 옛 이름을 뒤집어쓴 HTTP/2입니다.

증상

  • Chrome이 ERR_SPDY_PROTOCOL_ERROR를 표시하고 페이지가 비었거나 반만 그려집니다.
  • 같은 URL이 Firefox·Safari에서, 또는 다른 기기·네트워크의 Chrome에서 열립니다.
  • 캐시 비우기나 브라우저 재시작 후 잠깐 사라졌다가 다시 옵니다.
  • 어떤 환경에서는 간헐적입니다 — 사이트 대부분은 열리는데 한 엔드포인트만 어김없이 실패합니다.

이 오류가 실제로 뜻하는 것

SPDY는 구글이 HTTP를 빠르게 하려고 만든 실험 프로토콜입니다. 그 대부분이 HTTP/2에 흡수됐고, IETF가 2015년 5월 RFC 7540으로 표준화했습니다(현재는 RFC 9113이 갱신). 구글은 HTTP/2가 나온 지 정확히 1년 뒤인 2016년 5월, 버전 51에서 Chrome의 SPDY를 제거했습니다. 하지만 Chrome의 네트워크 스택은 내부 이름을 바꾸지 않았습니다 — 지금 HTTP/2를 말하는 코드가 여전히 SPDY에서 온 이름표를 달고 있어서, HTTP/2 세션의 실패가 ERR_SPDY_PROTOCOL_ERROR로 나타납니다. 실무적으로는 ERR_HTTP2_PROTOCOL_ERROR와 같은 것입니다: Chrome과 서버가 HTTP/2로 말하기로 합의했는데, 그 대화가 무너진 것.

이게 진단에 중요한 이유는 HTTP/2가 HTTP/1.1보다 훨씬 엄격하기 때문입니다. HTTP/1.1은 텍스트 프로토콜이라 어지간한 허술함 — 이상한 공백, 헤더의 특이한 문자, 대소문자 변덕 — 을 봐줍니다. HTTP/2는 바이너리이고 엄정합니다: RFC 9113 §8.2는 헤더 필드 이름을 소문자로 요구하고 필드 안의 잘못된 옥텟을 금지하며, 위반은 경고가 아니라 연결 오류입니다. 그래서 HTTP/1.1 위에서 몇 년째 절뚝이며 통과하던 응답 헤더가, 사이트가 HTTP/2로 서빙되는 순간 Chrome이 연결 전체를 헐어버리게 만들 수 있습니다. “옛 브라우저에선 되고 Chrome에선 깨진다”가 강한 단서인 이유가 이것입니다 — Chrome은 그 헤더가 조용히 어기고 있던 규칙을 집행하는 것입니다.

주요 원인 3가지

  1. 서버가 HTTP/2가 거부하는 헤더를 보냄 - 잘못된/비준수 응답 헤더 — 잘못된 문자, 대문자 필드 이름, 애플리케이션 프레임워크나 커스텀 모듈이 끼워 넣은 나쁜 바이트 — 는 HTTP/1.1에서는 그럭저럭 통하지만 HTTP/2에서는 치명적입니다. Chrome은 스트림을 끊습니다. 나머지 사이트는 되는데 특정 엔드포인트만 실패하는 전형적 원인입니다 — 나쁜 헤더가 실린 응답만 깨집니다.
  2. 중간 장비가 트래픽을 다시 쓰거나 망가뜨림 - VPN, 회사 프록시, TLS를 검사하는 백신(“HTTPS 검사”, “웹 보호”)은 HTTPS를 복호화했다가 다시 암호화하는데, 그 과정에서 HTTP/2 프레이밍을 손상시키거나 연결을 험하게 다운그레이드할 수 있습니다. 사이트가 아니라 그 보안 소프트웨어가 깔린 네트워크·기기를 따라 실패가 움직이는 게 신호입니다.
  3. Chrome의 낡은 로컬 상태 - 멈춘 소켓이나 손상된 캐시 항목이 한 오리진에 대한 Chrome의 HTTP/2 상태를 나쁜 지점에 남겨둘 수 있습니다. 재시작이나 캐시 비우기 후 “저절로 고쳐지는” 경우이고, 공짜라 가장 먼저 배제할 가치가 있습니다.

DechoNet으로 진단

  • HTTP 검사는 내 브라우저·네트워크 바깥에서 원본 응답 헤더를 읽습니다. 헤더가 잘못됐거나 필드가 비준수라면 여기서 보이고, 외부에서 깨끗이 받아지는데 Chrome만 못 연다면 내 로컬 네트워크나 프로필을 정확히 가리킵니다.
  • SSL 검사는 인증서와 TLS 핸드셰이크가 건강한지 확인해 암호 계층을 배제하게 합니다. ERR_SPDY_PROTOCOL_ERROR는 인증서 오류가 아니라 HTTP/2 전송 실패지만, TLS를 검사하는 중간 장비는 둘을 한꺼번에 깨므로 그런 장비를 찾는 데 도움이 됩니다.
  • 포트 검사는 443이 열려 있고 서버에 도달 가능한지 확인해, 진짜 연결 장애와 프로토콜 특유의 문제를 구분합니다.

해결 체크리스트

  • 로컬 상태부터 배제: chrome://net-internals/#sockets에서 Flush socket pools를 누르고, 캐시 데이터를 지운 뒤 새로고침. 공짜이고 “멈춘 소켓” 경우를 고칩니다.
  • 확장 프로그램을 끈 시크릿 창이나 새 프로필에서 테스트. 거기서 되면 확장이나 캐시가 원인이었습니다.
  • 다른 네트워크에서, 가능하면 TLS 검사 백신이나 VPN이 없는 기기에서 테스트. 오류가 그 네트워크·소프트웨어를 따라다니면 중간 장비가 HTTP/2를 망가뜨리는 것입니다.
  • 실패하는 URL에 HTTP 검사를 돌려 응답 헤더에서 잘못된 것 — 잘못된 문자, 대문자 필드 이름, 중복·과대 필드 — 을 살펴보세요.
  • 서버를 운영한다면: 실패하는 정확한 엔드포인트와 그것이 내보내는 헤더를 보세요. 비준수 헤더를 근원에서 고칩니다. 임시로 오리진·CDN에서 HTTP/2를 꺼 HTTP/1.1을 강제하면 오류가 사라지지만 — 그건 나쁜 헤더를 찾는 동안의 우회일 뿐, 해결이 아닙니다.

이럴 땐 넘기세요(에스컬레이션)

  • HTTP 검사가 TCP 위에서 깨끗하고 준수하는 응답을 보여주는데도 Chrome이 실패하고 문제가 한 네트워크를 따라간다면, 네트워크 팀에 넘기세요 — 프록시나 검사 장비가 HTTP/2를 깨는 것이고, 지속적 해결은 모든 데스크톱이 아니라 거기 있습니다.
  • CDN을 거치는 한 엔드포인트에만 실패가 국한된다면, CDN이나 애플리케이션 팀에 넘기세요 — 그 경로에서 나오는 응답 헤더가 HTTP/2를 위반하고 있으며 오리진에서 고쳐야 합니다.
  • 오류를 없애려 HTTP/2를 끄는 건 서버가 보내면 안 되는 헤더를 숨기는 것입니다. HTTP/1.1로 연명하며 피하지 말고 그 헤더를 찾아 고치세요.

내 도메인에서 바로 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.