ERR_HTTP2_PROTOCOL_ERROR 오류 원인과 해결 방법

Advertisement
ERR_HTTP2_PROTOCOL_ERROR란?
ERR_HTTP2_PROTOCOL_ERROR는 브라우저가 프로토콜 규칙을 어긴 HTTP/2 응답을 받았다는 뜻의 Chrome·Edge 오류입니다. Chromium 내부에서는 네트워크 오류 -337이며, "there is an HTTP/2 protocol error", 즉 HTTP/2 프로토콜 오류가 있다고 설명되어 있습니다. Chrome에는 이 오류 전용 페이지가 없어 일반 오류 페이지가 표시됩니다. '사이트에 연결할 수 없음'과 함께 해당 웹페이지가 일시적으로 다운되었거나 새 웹 주소로 영구적으로 이동했을 수 있다는 문구(영문: "This site can't be reached. The webpage at … might be temporarily down or it may have moved permanently to a new web address")가 나오고, 그 아래에 ERR_HTTP2_PROTOCOL_ERROR가 표시됩니다.
HTTP/2는 현재 대부분의 HTTPS 사이트가 사용하는 더 빠른 버전의 HTTP입니다. HTTP/1.1보다 엄격해서, 응답은 바이너리 프레임으로 나뉘고, 헤더는 정확한 규칙을 따라야 하며, 선언된 응답 크기는 실제로 도착한 크기와 일치해야 합니다. 스트림 도중 끊기거나 금지된 헤더가 들어 있는 등 이 규칙을 어긴 응답을 보면, Chrome은 응답 전체를 잘못된 형식으로 간주해 버립니다.
개발자들은 개발자 도구 콘솔에서 net::ERR_HTTP2_PROTOCOL_ERROR 200 (OK) 형태로 자주 봅니다. 이 조합은 강력한 단서입니다. 서버는 200으로 응답했지만 응답 본문이 온전히 도착하지 못했다는 뜻이기 때문입니다.
HTTP/2가 잘못된 형식으로 간주하는 것
HTTP/2 표준(RFC 9113)은 응답을 잘못된 형식으로 만드는 실수들을 나열하며, 끝나기 전에 리셋된 스트림도 실패로 처리됩니다. 실제로 발생하는 오류 대부분은 다음 문제 때문입니다:
| 규칙 | 규칙을 어기는 경우 |
|---|---|
| Content-Length는 본문 크기와 같아야 함 | 서버나 플러그인이 한 크기를 선언하고 다른 크기를 보냄. 예: 길이를 설정한 뒤 출력을 압축하는 경우 |
| 응답은 깔끔하게 끝나야 함 | 서버, 프록시, 앱이 전송 도중 멈춤 |
| 연결 전용 헤더 금지 | HTTP/2 응답에 Connection, Keep-Alive, Proxy-Connection, Transfer-Encoding, Upgrade를 보냄 |
| 필드 이름은 소문자여야 함 | 대문자가 포함된 헤더 이름이 그대로 HTTP/2로 전달됨 |
| 유효한 헤더 값 | 헤더 값 안에 줄바꿈이나 기타 금지된 문자가 있음 |
| 유효한 :status 줄 | 상태 코드가 없거나 읽을 수 없음 |
Advertisement
ERR_HTTP2_PROTOCOL_ERROR의 원인
대부분은 서버 쪽에서 발생하지만, 내 컴퓨터의 몇 가지 요소가 들어오는 응답을 손상시킬 수도 있습니다:
서버 쪽: 스트림 도중 잘린 응답(디스크 공간이 부족하거나 임시 파일을 쓸 수 없는 프록시, 스트리밍 중 크래시하는 앱, 타임아웃), 잘못된 Content-Length 값, 금지되었거나 유효하지 않은 헤더, 오래된 서버나 CDN 설정의 버그 있는 HTTP/2 지원.
내 쪽: HTTPS를 검사하며 응답을 다시 쓰는 백신이나 방화벽 소프트웨어, 요청이나 응답을 수정하는 브라우저 확장 프로그램, 손상된 페이지 캐시, 그리고 가끔은 오래된 Chrome 버전.
해결 방법 1: 강력 새로고침 후 시크릿 창에서 열기
Ctrl + Shift + R(Mac: Cmd + Shift + R)을 눌러 캐시 없이 새로고침하세요. 한 번 잘렸던 응답이 다음 시도에서는 정상적으로 도착할 수 있습니다.
그다음 시크릿 창(Ctrl + Shift + N, Mac Cmd + Shift + N)에서 페이지를 열어 보세요. 시크릿 창에는 쿠키도, 평소 프로필의 캐시도 없고 확장 프로그램도 기본적으로 꺼져 있습니다. 여기서 페이지가 열린다면 해결 방법 2나 해결 방법 3으로 평소 창에서도 해결됩니다.
Advertisement
해결 방법 2: 해당 사이트의 캐시와 쿠키 삭제하기
손상된 캐시나 비대해진 쿠키는 한 사이트에서 이 오류를 반복적으로 일으킬 수 있습니다. 해당 사이트의 데이터만 지우세요: 주소창 왼쪽 아이콘 클릭 → 쿠키 및 사이트 데이터(또는 사이트 설정) → 데이터 삭제 후 새로고침. 더 넓게 정리하려면 Ctrl + Shift + Delete를 누르고 최근 며칠간의 캐시된 이미지 및 파일을 지우세요.
해결 방법 3: 백신 HTTPS 검사와 확장 프로그램 일시 중지
HTTPS를 복호화해 검사하는 보안 소프트웨어는 모든 HTTP/2 연결의 중간에 자리 잡고 있습니다. 이 소프트웨어의 HTTP/2 처리에 버그가 있거나 오래되었다면 Chrome이 잘못된 형식으로 보는 응답을 그대로 넘길 수 있습니다. HTTPS 검사 기능(HTTPS 검사, 웹 실드(Web Shield), SSL/TLS 프로토콜 필터링, 암호화된 연결 검사 등으로 불림)만 끄고 새로고침하세요. 그것으로 해결된다면 백신을 업데이트하고 해당 사이트를 예외로 추가하세요.
다음으로 chrome://extensions에서 모든 확장 프로그램을 끄고 새로고침한 뒤, 하나씩 다시 켜 보세요. 광고 차단기, 개인정보 보호 도구, 헤더를 수정하는 확장 프로그램이 주요 용의자입니다.
Advertisement
해결 방법 4: Chrome 업데이트 및 다른 브라우저 확인
chrome://settings/help를 열어 대기 중인 업데이트를 설치한 뒤 브라우저를 다시 시작하세요. 그다음 같은 페이지를 Firefox나 Safari에서 열어 보세요. 모든 브라우저에서 실패한다면 사이트가 고장 난 것이며 운영자만 해결할 수 있습니다. Chrome이나 Edge에서만 실패하더라도 대개는 여전히 사이트 문제입니다. Chrome이 잘못된 형식의 HTTP/2를 가장 엄격하게 거부하기 때문입니다. 다만 해결 방법 2와 3은 한 번 더 시도해 볼 만합니다.
해결 방법 5: HTTP/2 없이 페이지 테스트하기
Chrome은 HTTP/2를 끈 상태로 실행할 수 있으며, 이렇게 하면 HTTP/2가 문제인지 확실히 알 수 있습니다. 먼저 모든 Chrome 창을 닫은 뒤 터미널에서 실행하세요:
# Windows (명령 프롬프트)
"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-http2
# macOS (터미널)
open -a "Google Chrome" --args --disable-http2이 창에서 페이지가 열린다면 사이트의 HTTP/2 응답이 잘못된 형식이므로 운영자가 고쳐야 합니다. 확인이 끝나면 Chrome을 닫고 평소처럼 다시 여세요. 이 플래그는 그 한 번의 실행에만 적용됩니다.
Advertisement
웹사이트 운영자용: HTTP/2 프로토콜 오류 해결하기
서로 다른 네트워크와 브라우저를 쓰는 방문자들이 이 오류를 보고한다면 문제는 내 서버 스택에 있습니다. 다음 세 가지 점검으로 거의 모든 원인을 찾을 수 있습니다.
1. curl로 재현하기
# HTTP/2: 출력의 마지막 부분을 확인하세요
curl -sv --http2 https://example.com/broken-page -o /dev/null
# 깨진 스트림은 다음과 비슷한 줄로 끝납니다:
# HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
# (curl 8.19+: HTTP/2 stream 1 reset by server (error 0x1 PROTOCOL_ERROR))
# 비교를 위해 같은 URL을 HTTP/1.1로 요청
curl -sv --http1.1 https://example.com/broken-page -o /dev/nullHTTP/1.1은 작동하고 HTTP/2는 실패한다면 오류가 확인된 것입니다. 두 응답의 헤더를 비교하고, 스트림이 끊기기 전까지 몇 바이트가 도착했는지 기록하세요. HTTP 헤더 확인 도구로도 내 네트워크 바깥에서 사이트가 보내는 헤더를 확인할 수 있습니다.
2. 스트림 도중 잘린 응답 확인하기
서버 쪽에서 가장 흔한 원인은 응답이 시작된 뒤(상태 200, 헤더 전송 완료) 일찍 멈추는 경우입니다. nginx는 앱에서 오는 큰 응답을 임시 파일에 버퍼링하는데, 디스크가 가득 찼거나 nginx가 임시 폴더에 쓸 수 없으면 응답이 일찍 끝나고 브라우저는 프로토콜 오류를 보고합니다. 다음을 확인하세요:
df -h # 가득 찬 디스크가 있나요?
sudo grep -E "No space left|Permission denied" /var/log/nginx/error.log | tail
ls -ld /var/lib/nginx/proxy /var/lib/nginx/fastcgi # Debian/Ubuntu 임시 디렉터리. 소유자가 nginx 사용자와 일치해야 함앱 자체도 확인하세요. 큰 페이지나 다운로드를 스트리밍하는 도중 크래시하거나, 타임아웃되거나, 메모리 제한에 걸리는 PHP나 Node 프로세스도 같은 결과를 냅니다. 오류 발생 시각 전후의 앱 로그에 대개 흔적이 남아 있습니다.
3. Content-Length와 금지된 헤더 수정하기
Content-Length: 서버가 계산하게 두세요. 플러그인, 미들웨어, 웹 서버가 출력을 압축하거나 수정한다면 앱 코드에서 직접 설정하지 마세요. 선언된 길이가 실제로 전송된 바이트와 더 이상 일치하지 않게 됩니다. WordPress 사이트에서는 PHP 코드에서 길이를 설정했는데 플러그인이나 PHP 설정이 출력을 압축할 때 이런 일이 생기곤 합니다.
연결 전용 헤더: 응답에
Connection,Keep-Alive,Transfer-Encoding,Upgrade를 설정하는 코드를 제거하세요. HTTP/2는 이 헤더들을 금지하며, nginx는 대부분 자동으로 제거해 주지만 일부 앱 서버와 프록시는 그렇지 않습니다.헤더 값: 어떤 헤더에도 줄바꿈이나 제어 문자가 없는지 확인하세요.
Content-Disposition의 파일 이름처럼 사용자 입력을 헤더에 넣을 때 자주 발생합니다.앞단의 CDN: Cloudflare 등 CDN을 사용한다면 원본 서버를 직접 테스트해(curl
--resolve또는 hosts 파일 항목 사용) 오류가 원본에서 오는지 CDN에서 오는지 구분하세요.
ERR_HTTP2_PROTOCOL_ERROR와 비슷한 오류 비교
| 오류 | 코드 | 무슨 일이 일어났나 |
|---|---|---|
| ERR_HTTP2_PROTOCOL_ERROR | -337 | HTTP/2 응답이 프로토콜 규칙을 어김 |
| ERR_QUIC_PROTOCOL_ERROR | -356 | HTTP/3(QUIC)에서 발생한 같은 종류의 실패 |
| ERR_SSL_PROTOCOL_ERROR | -107 | HTTP/2가 시작되기 전에 HTTPS(TLS) 핸드셰이크가 실패함 |
| ERR_CONNECTION_CLOSED | -100 | 페이지가 도착하기 전에 연결이 닫힘 |
| ERR_EMPTY_RESPONSE | -324 | 서버가 아무것도 보내지 않음 |
자세한 가이드: ERR_QUIC_PROTOCOL_ERROR, ERR_SSL_PROTOCOL_ERROR, ERR_CONNECTION_CLOSED, ERR_EMPTY_RESPONSE. 사이트의 인증서와 HTTPS 설정을 외부에서 확인하려면 SSL 인증서 확인 도구를 사용하세요.
내 사이트가 실제로 보내는 헤더를 확인하세요
DNS Robot의 HTTP 헤더 확인 도구는 저희 서버에서 모든 URL을 요청해 상태 코드와 모든 응답 헤더를 보여 줍니다. 금지되었거나 잘못된 형식의 헤더를 쉽게 찾을 수 있습니다.
사용해보기 HTTP 헤더 확인Advertisement
자주 묻는 질문
Chrome이 프로토콜 규칙을 어긴 HTTP/2 응답을 받아 그 응답을 버렸다는 뜻입니다. 일찍 끝났거나, 크기를 잘못 선언했거나, 금지된 헤더가 들어 있는 응답이 그 예입니다. Chromium에서는 네트워크 오류 -337입니다.