در کروم یک برنامه تحت وب، صفحه پرداخت یک فروشگاه یا صفحه یک سرویس ویدیویی را باز میکنید و به جای آن صفحهای خاکستری میبینید: عنوان «نمیتوان به این سایت دست یافت» (در رابط انگلیسی "This site can't be reached")، سطری که میگوید صفحه وب ممکن است «موقتاً خراب باشد یا ممکن است برای همیشه به آدرس وب جدید منتقل شده باشد» و در پایین صفحه ERR_HTTP2_PROTOCOL_ERROR. گاهی هم صفحه نیمهکاره بارگذاری میشود، یک اسکریپت یا تصویر جا میماند و کنسول ابزارهای برنامهنویس مرورگر سطر "Failed to load resource: net::ERR_HTTP2_PROTOCOL_ERROR" را نشان میدهد.
این کد به HTTP/2 اشاره دارد، پروتکلی که بیشتر سایتهای امن با کروم از آن استفاده میکنند، و تقریباً همیشه یعنی سایت، یا دستگاهی میان شما و سایت، چیزی فرستاده که قواعد HTTP/2 را زیر پا میگذارد. در ادامه میخوانید این کد چه معنایی دارد، یک درخواست چگونه میشکند، کدام علتها را بازسازی کردیم، بازدیدکنندگان چه راهحلهایی دارند، صاحبان سایت در nginx، IIS و Cloudflare چه چیزهایی را بررسی میکنند و این خطا در Go، Node.js و Python چه شکلی دارد.
خطای ERR_HTTP2_PROTOCOL_ERROR یعنی چه؟
یعنی به اتصال HTTP/2 میان مرورگر و سایت چیزی رسیده که پروتکل اجازه نمیدهد و درخواست نتوانسته کامل شود. HTTP/2 دومین نسخه اصلی HTTP است؛ درون یک اتصال رمزگذاریشده با TLS روی پورت 443 در TCP اجرا میشود و سرور آن را هنگام دستدادن TLS با شناسه h2 انتخاب میکند. کروم و اج بر کرومیوم ساخته شدهاند و فهرست خطاهای شبکه کرومیوم این کد را با شماره -337 و در یک سطر تعریف میکند: "There is an HTTP/2 protocol error." (یک خطای پروتکل HTTP/2 وجود دارد).
این سطر نشانه را نام میبرد، نه مقصر را. استاندارد HTTP/2 کد PROTOCOL_ERROR را بهعنوان کد عمومی برای حالتهایی نگه داشته که «کد خطای مشخصتری در دسترس نیست»؛ پس پیام میگوید قاعدهای شکسته شده، بیآنکه بگوید کدام. خطای همخانواده آن، ERR_QUIC_PROTOCOL_ERROR، به HTTP/3 روی QUIC و UDP مربوط است و علتهای دیگری دارد؛ آن را در رفع خطای err_quic_protocol_error در کروم و اج توضیح دادهایم.
صفحه خطا به شما چه میگوید؟
| سطر روی صفحه | یعنی چه |
|---|---|
| «نمیتوان به این سایت دست یافت» | عنوان عمومی کروم برای درخواستی که پیش از نمایش صفحه شکست خورده است |
| «ممکن است صفحهٔ وب example.com موقتاً خراب باشد یا ممکن است برای همیشه به آدرس وب جدید منتقل شده باشد.» | یک جمله پیشفرض، نه تشخیص؛ سایت معمولاً در دسترس است |
ERR_HTTP2_PROTOCOL_ERROR | تنها اطلاعات مشخص روی صفحه |
خود صفحه را در کرومیوم 145 دیدیم و متن فارسی این سطرها از فایلهای ترجمه فارسی کرومیوم آمده است. صفحه نه فهرست «این موارد را امتحان کنید:» (در رابط انگلیسی "Try:") دارد و نه دکمه بارگذاری مجدد: کرومیوم برای خطاهای HTTP/2 متن ویژهای ندارد و به صفحه عمومی خود برمیگردد. اج همین کد را نشان میدهد؛ کدهای دیگری که زیر این عنوان ظاهر میشوند در خطای This Site Can't Be Reached توضیح داده شدهاند.
وقتی اتصال پس از آنکه سرور هدر 200 OK را فرستاده قطع شود، ممکن است صفحه ناقص به نظر برسد و کنسول ابزارهای برنامهنویس (F12) برای درخواستی که بریده شده سطر "Failed to load resource: net::ERR_HTTP2_PROTOCOL_ERROR" را ثبت میکند. عدد 200 کنار خطا دقیقاً همین را میگوید: پاسخ پیش از آنکه جریان (stream) بازنشانی شود، شروع شده بود.
یک درخواست HTTP/2 چگونه میشکند؟
- اتصال آغاز میشود. کروم یک اتصال TLS به پورت 443 باز میکند و
h2را پیشنهاد میدهد؛ سرور میپذیرد و هر دو طرف یک فریمSETTINGSبا محدودیتهای خود رد و بدل میکنند. - درخواستها به شکل جریان حرکت میکنند. هر درخواست جریان خودش را روی اتصال مشترک میگیرد که فریمهای
HEADERSرا برای هدرها و فریمهایDATAرا برای بدنه حمل میکند. - یک فریم قاعدهای را میشکند. RFC 9113، استاندارد HTTP/2، پیامی را بدشکل (malformed) میداند که در آن
Content-Lengthبا مجموع فریمهایDATAبرابر نباشد، مقدار یک هدر با فاصله شروع یا تمام شود، یا هدری مخصوص اتصال مانندConnectionیاTransfer-Encodingوجود داشته باشد. - طرفی که متوجه میشود جریان را بازنشانی میکند. با پیام بدشکل باید مانند یک خطای جریان از نوع
PROTOCOL_ERRORرفتار شود، پس آن طرف یک فریمRST_STREAMمیفرستد و جریان را بازنشانی (reset) میکند؛ خطایی که کل اتصال را خراب کند به فریمGOAWAYتبدیل میشود و اتصال بسته میشود. - کروم
-337را گزارش میکند. وقتی کروم یکRST_STREAMباPROTOCOL_ERRORدریافت کند، یا خودش فریم نامعتبری را تشخیص دهد، آن درخواست را باERR_HTTP2_PROTOCOL_ERRORشکستخورده اعلام میکند. کرومیوم آن را دوباره امتحان نمیکند و به HTTP/1.1 برنمیگردد؛ فقط کدHTTP_1_1_REQUIREDاست که کروم را وادار میکند درخواست را با پروتکل قدیمیتر دوباره بفرستد.
علتهای خطای ERR_HTTP2_PROTOCOL_ERROR کداماند؟
| علت | نشانه معمول | چه کسی رفعش میکند |
|---|---|---|
برنامه سایت پاسخی میفرستد که قواعد HTTP/2 را میشکند: یک هدر ممنوع، یک Content-Length نادرست، مقدار هدری با فاصله در انتها | یک سایت یا یک صفحه، برای همه بازدیدکنندگان | صاحب سایت |
| یک CDN یا ریورس پروکسی (سرور واسطی جلوی سایت) پاسخ بدشکل سرور مبدأ (origin) را رد میکند و جریان شما را بازنشانی میکند | از طریق CDN خطا میدهد، از سرور مبدأ باز میشود | صاحب سایت |
| هدرهای پاسخ بزرگتر از محدودیت سرور یا CDN، معمولاً بهخاطر کوکیهای بسیار بزرگ | یک سایت، پس از ورود به حساب | صاحب سایت؛ حذف دادههای سایت همین حالا کمک میکند |
| پیادهسازی قدیمی یا بدتنظیم HTTP/2 روی سرور | یک سایت، اغلب درست پس از فعال شدن HTTPS | صاحب سایت |
| نرمافزار امنیتی، فایروال یا فیلتری که TLS را بازرسی میکند و فریمها را تغییر میدهد | سایتهای زیاد، در یک رایانه یا یک شبکه | شما، یا واحد فناوری اطلاعات |
| یک VPN یا برنامه «محافظت» که ترافیک را از خودش عبور میدهد | فقط وقتی برنامه اجرا میشود | شما |
روی سرور آزمایشی HTTP/2 ما، کرومیوم 145 یک Content-Length بزرگتر از بدنه را تحمل کرد و حتی صفحه بریدهشده را نمایش داد، در حالی که کلاینت HTTP/2 در Node.js، کتابخانه httpx در Python و undici همان پاسخ را با PROTOCOL_ERROR رد کردند؛ وقتی خود سرور جریان را بازنشانی کرد، کرومیوم بلافاصله ERR_HTTP2_PROTOCOL_ERROR نشان داد. الگوی رایج در دنیای واقعی همین است: پاسخی کمی خراب که مرورگر آن را میپذیرفت، در CDN یا متعادلکننده بار (load balancer) سختگیرتری که جلوی سایت نشسته رد میشود و همان، جریان بازدیدکننده را بازنشانی میکند.
بهعنوان بازدیدکننده چگونه رفعش کنید؟
اگر سایتهای امن دیگر هم خطا میدهند، علت سمت شماست؛ اگر سایت در گوشی شما با وایفای خاموش هم خطا میدهد، علت از سایت است. پس از هر گام صفحه را دوباره بارگذاری کنید.
- یک بار دوباره بارگذاری کنید. در بالای پنجره (در رابط فارسی سمت راست)، بار کردن مجدد این صفحه را انتخاب کنید.
- یک پنجره ناشناس یا مرورگر دیگری را امتحان کنید. بیشتر > پنجره ناشناس جدید را باز کنید؛ اگر صفحه آنجا باز شد، افزونهها را در بیشتر > افزونهها > مدیریت افزونهها یکییکی خاموش کنید.
- VPN و برنامههای فیلتر را قطع کنید، از جمله برنامههایی که تبلیغات را با عبور دادن ترافیک از خودشان مسدود میکنند.
- محافظت وب آنتیویروس را برای یک آزمایش متوقف کنید. برنامههایی که ترافیک HTTPS را اسکن میکنند درون اتصال رمزگذاریشده مینشینند. فقط همان قابلیت را خاموش کنید، یک بار دوباره بارگذاری کنید و سپس آن را دوباره روشن کنید؛ اگر توقف کمک کرد، برنامه را بهروز کنید.
- دادههای ذخیرهشده سایت را حذف کنید. بیشتر > تنظیمات و سپس حریم خصوصی و امنیت > کوکیهای طرف سوم > دیدن همه دادهها و اجازههای سایت را انتخاب کنید، سایت را جستوجو کنید، حذف را انتخاب کنید و با حذف تأیید کنید.
- کروم را بهروز کنید. بیشتر > راهنما > درباره Google Chrome را انتخاب کنید و اگر راهاندازی مجدد ظاهر شد، آن را بزنید.
- در شبکه محل کار یا مدرسه از واحد فناوری اطلاعات (IT) بپرسید. فایروالی که ترافیک را بازرسی میکند متعلق به سازمان است و راهحل هم همینطور.
در اندروید، کروم را از فروشگاه Play بهروز کنید: روی نماد نمایه و سپس مدیریت برنامهها و دستگاه ضربه بزنید و در بخش «بهروزرسانی دردسترس است» کنار Chrome روی بهروزرسانی ضربه بزنید. برای حذف دادههای ذخیرهشده، کروم را باز کنید، روی بیشتر > حذف دادههای مرور ضربه بزنید، نوع دادهها را انتخاب کنید و روی حذف دادهها ضربه بزنید. پیش از آنکه سایت را مقصر بدانید، میان وایفای و اینترنت همراه جابهجا شوید و هر برنامه VPN را خاموش کنید.
اگر سایت مال شماست: پاسخ خراب را چگونه پیدا کنید
- درخواست را مشخص کنید. در DevTools پنل شبکه (Network) را باز کنید، صفحه را دوباره بارگذاری کنید و درخواستی را بیابید که با این خطا شکستخورده علامت خورده است؛ ستون پروتکل (Protocol)، که با راستکلیک روی سرستون جدول فعال میشود،
h2را نشان میدهد. - از خط فرمان دو بار درخواست کنید.
curl --http2 -v https://example.com/pathوcurl --http1.1 -vبا همان آدرس، دو پروتکل را تحمیل میکنند و هدرهای پاسخ را چاپ میکنند. اگر HTTP/2 شکست بخورد و HTTP/1.1 صفحه را برگرداند، پاسخ یکی از قواعد HTTP/2 را میشکند. curl همراه ویندوز 11 گزینه--http2را رد میکند ("the installed libcurl version does not support this")، پس آزمایش را در لینوکس، macOS یا روی خود سرور انجام دهید. - سرور مبدأ را با لبه (edge) مقایسه کنید. پشت یک CDN یا متعادلکننده بار، همان آدرس را یک بار مستقیم از سرور مبدأ و یک بار از طریق آدرس عمومی، یعنی لبه، درخواست کنید و هدرها را مقایسه کنید:
Content-LengthوContent-Encoding، هر هدرConnection،Keep-AliveیاTransfer-Encodingو مقدارهایی که در انتها فاصله دارند. - پاسخ را درست کنید، نه پروتکل را. میانافزار فشردهسازیای که بدنه را پس از آنکه برنامه
Content-Lengthرا تنظیم کرده با gzip فشرده میکند، علت کلاسیک است؛ بگذارید فقط یک لایه فشرده کند و طول را دوباره محاسبه کند. هدرهای مخصوص اتصال را از کد برنامه حذف کنید و کوکیها را کوچک نگه دارید. خاموش کردن HTTP/2 روی سرور یک گام تشخیصی چند دقیقهای است، نه راهحل: پاسخ بدشکل میماند و کلاینت سختگیر بعدی دوباره شکست میخورد. - nginx. نسخههای فعلی HTTP/2 را با دستور
http2 on;کنارlisten 443 ssl;فعال میکنند که از نسخه 1.25.1 در دسترس است؛ شکل قدیمیlisten 443 ssl http2;منسوخ شده وhttp2_max_field_sizeوhttp2_max_header_sizeاز نسخه 1.19.7 کنار گذاشته شدهاند وlarge_client_header_buffersجای آنها را گرفته است، همانطور که مستندات ngx_http_v2_module توضیح میدهد. - IIS. طبق مقاله مایکروسافت درباره HTTP/2 در IIS، IIS 10 در ویندوز سرور 2016 و بعد از آن HTTP/2 را فقط روی TLS صحبت میکند و برای احراز هویت ویندوز به HTTP/1.1 برمیگردد؛ فیلد "Protocol version" در Logging (گزارشگیری) > Select Fields (انتخاب فیلدها) نشان میدهد کدام درخواستها از HTTP/2 استفاده میکنند. برای آزمایش، ویندوز میتواند HTTP/2 را بهازای هر binding گواهی TLS با
netsh http update sslcert ... disablehttp2=enableخاموش کند (از مستنداتnetsh http؛ ما آن را اجرا نکردیم). - Cloudflare. HTTP/2 در همه پلنها بهطور پیشفرض روشن است و صفحه HTTP/2 در Cloudflare هدرهای بدقالب سرور مبدأ و مشکلات فشردهسازی، مانند gzip بدون بهروز کردن
Content-Length، را علتهای معمول در سایتهای پروکسیشده میداند و پیشنهاد میکند فشردهسازی را به Cloudflare بسپارید.
توسعهدهندگان و اسکرپرها: همان خطا در Go، Node.js و Python
کلاینتهای HTTP که h2 را مذاکره میکنند درست مانند کروم شکست میخورند. http.Server و http.DefaultTransport در Go برای HTTPS بهطور خودکار از HTTP/2 استفاده میکنند (GODEBUG=http2client=0 سمت کلاینت را خاموش میکند). در Node.js 24.22، fetch داخلی با سرور آزمایشی ما HTTP/1.1 صحبت کرد، در حالی که یک Agent از undici که با allowH2: true ساخته شده بود HTTP/2 را مذاکره کرد. در Python، httpx به pip install httpx[http2] و httpx.Client(http2=True) نیاز دارد؛ HTTP/2 بهطور پیشفرض خاموش است. در برابر پاسخی که Content-Length آن 100 بایت وعده میداد اما 5 بایت تحویل میداد، کلاینتهای ما این را گزارش کردند:
# Node.js 24.22, node:http2
response: :status=200 content-length=100 content-type=text/plain
stream error: ERR_HTTP2_STREAM_ERROR Stream closed with error code NGHTTP2_PROTOCOL_ERROR
# undici 7.30 with allowH2: true
TypeError: terminated <- ERR_HTTP2_STREAM_ERROR: Stream closed with error code NGHTTP2_PROTOCOL_ERROR
# Python httpx 0.28 with http2=True
h2.exceptions.InvalidBodyLengthError: InvalidBodyLengthError: Expected 100 bytes, received 5با یک خطای پروتکل HTTP/2 مانند یک پاسخ بدشکل رفتار کنید، نه مانند یک مسدودسازی: برای اطمینان یک بار روی HTTP/1.1 دوباره امتحان کنید، اگر سرور مال شماست درستش کنید و اگر نیست، آدرس و هدرها را به صاحب آن گزارش دهید. تغییر آیپی هیچ فایدهای ندارد؛ هر آدرسی همان پاسخ خراب را دریافت میکند.
پروکسی بهندرت وارد این ماجرا میشود. برای یک سایت https://، کلاینت با یک درخواست CONNECT از پروکسی یک تونل میخواهد و TLS را، با HTTP/2 درون آن، بهصورت سرتاسری با سایت اجرا میکند؛ پروکسی هرگز فریمی نمیبیند، پس یک پروکسی HTTPS نه این خطا را ایجاد میکند و نه آن را رفع میکند. فقط پروکسیای که عمداً TLS را پایان میدهد، مانند یک گیتوی بازرسی سازمانی، خودش یک نقطه پایانی مستقل HTTP/2 است.
یک مسیر خروج دوم، خرابی سراسری را از خرابی منطقهای جدا میکند: درخواست را از طریق یک پروکسی دیتاسنتر در کشوری دیگر تکرار کنید؛ همان خطا در آنجا یعنی پاسخ برای همه خراب است و پاسخ سالم به شبکه خودتان یا نرمافزار بازرسی اشاره میکند.
خطاهای مرتبط
| کد | شماره | یعنی چه |
|---|---|---|
ERR_HTTP2_PROTOCOL_ERROR | -337 | یک قاعده HTTP/2 شکسته شد؛ درخواست لغو شد |
ERR_HTTP2_SERVER_REFUSED_STREAM | -351 | سرور جریان را پیش از پردازش رد کرد؛ کروم ممکن است دوباره امتحان کند |
ERR_HTTP_1_1_REQUIRED | -365 | سرور HTTP/1.1 خواست؛ کروم درخواست را با آن دوباره میفرستد |
ERR_QUIC_PROTOCOL_ERROR | -356 | اتصال HTTP/3 روی QUIC شکست |
اگر به جای آن ERR_SSL_PROTOCOL_ERROR میبینید، نوبت به HTTP/2 هرگز نرسیده است؛ رفع خطای err_ssl_protocol_error در کروم و اج آن حالت را پوشش میدهد.
کجا ممکن است با آن روبهرو شوید؟
- برنامههای تحت وب پشت یک CDN یا متعادلکننده بار، جایی که یک پاسخ API هدری دستی اضافهشده دارد.
- برنامههای ASP.NET و دیگر برنامههای میزبانیشده روی IIS اندکی پس از فعال شدن HTTPS، چون HTTP/2 در IIS فقط روی TLS وجود دارد.
- صفحههای سرویسهای ویدیویی که درخواستهای پخشکننده شکست میخورند در حالی که بقیه صفحه بارگذاری میشود.
اشتباههای رایج
- پاک کردن پیاپی کل حافظه پنهان (کش) مرورگر. فقط کوکیهای سایت مشکلدار اهمیت دارند، آن هم فقط وقتی علت هدرهای بیش از حد بزرگ است.
- درست کردن ساعت سیستم. تاریخ نادرست هشدار گواهی میدهد، نه این کد را.
- خاموش کردن QUIC در
chrome://flags. آن پرچم به HTTP/3 مربوط است؛ HTTP/2 در کروم کلیدی ندارد. - چرخاندن آیپی در اسکرپر. پاسخ برای هر آدرسی خراب است.
راهنمای انتخاب
| وضعیت شما | چه کنید |
|---|---|
| یک سایت در همه دستگاهها و شبکهها خطا میدهد | سایت یا CDN آن؛ به صاحب سایت خبر دهید و آدرس مشکلدار را بفرستید |
| سایتهای زیادی در یک رایانه خطا میدهند | نخست افزونهها، سپس محافظت وب آنتیویروس، سپس VPN یا برنامههای فیلتر |
| فقط یک شبکه آن را نشان میدهد | بازرسی TLS در آن شبکه؛ از کسی که شبکه را اداره میکند بپرسید |
| صفحه نیمهکاره بارگذاری میشود و کنسول خطا دارد | سرور پس از 200 جریان را بازنشانی کرده است؛ صاحب سایت باید آن پاسخ را بررسی کند |
| سایت مال شماست و پشت Cloudflare یا متعادلکننده بار است | هدرها و Content-Length سرور مبدأ را با لبه مقایسه کنید |
پرسشهای متداول
خطای ERR_HTTP2_PROTOCOL_ERROR را در اندروید چگونه رفع کنم؟
کروم را از فروشگاه Play بهروز کنید، میان وایفای و اینترنت همراه جابهجا شوید و هر برنامه VPN یا مسدودکننده تبلیغات را خاموش کنید. اگر سایت با اینترنت همراه هم خطا میدهد، علت سایت یا CDN آن است.
چرا لاگ سرور من 200 OK نشان میدهد در حالی که بازدیدکنندگان خطا میبینند؟
چون سطر وضعیت پیش از بازنشانی جریان فرستاده و ثبت شده است. برنامه با 200 پاسخ داد و سپس سرور، یک CDN یا مرورگر بقیه پاسخ را بدشکل یافت و جریان را لغو کرد.
آیا این خطا در سایتهای Cloudflare بیشتر رخ میدهد؟
آنجا بیشتر دیده میشود، چون لبه Cloudflare یک نقطه پایانی سختگیر HTTP/2 میان سرور مبدأ و بازدیدکننده است. پاسخی که مرورگر شاید مستقیم از مبدأ تحمل میکرد، در لبه رد میشود.
آیا میتوانم HTTP/2 را در کروم خاموش کنم؟
نه. تنظیمات کروم کلیدی برای HTTP/2 ندارد و پرچم QUIC در chrome://flags به HTTP/3 مربوط است. در سمت سرور با curl --http1.1 و curl --http2 آزمایش کنید؛ در سمت کلاینت، فایرفاکس سریعترین نظر دوم است.
آیا ERR_HTTP2_PROTOCOL_ERROR نشانه هک شدن رایانه من است؟
معمولاً نه؛ بیشتر موارد به سرور سایت، CDN آن یا نرمافزار امنیتی روی رایانه شما برمیگردد.
آیا VPN یا پروکسی خطای ERR_HTTP2_PROTOCOL_ERROR را رفع میکند؟
نه وقتی پاسخ سایت خراب است، چون همان فریمها از هر مسیری به شما میرسند. VPN یا پروکسی بازرسیکننده بیشتر علت است تا درمان.
خلاصه
ERR_HTTP2_PROTOCOL_ERROR یعنی فریمی در اتصال HTTP/2 کروم قواعد پروتکل را شکسته است، در بیشتر موارد چون سایت یا CDN آن پس از یک پاسخ بدشکل درخواست را بازنشانی کرده است: یک هدر ممنوع، یک Content-Length که دیگر با بدنه فشردهشده نمیخواند، یا هدرهای بیش از حد بزرگ. بازدیدکنندگان پنجره ناشناس، مرورگر دیگر و توقف VPN یا آنتیویروس را آزمایش میکنند؛ صاحبان سایت پاسخ را روی HTTP/1.1 و HTTP/2 مقایسه میکنند و به جای خاموش کردن HTTP/2 آن را درست میکنند. برای بررسی از چند مکان، انواع پروکسی در صفحه پروکسی ما مقایسه شدهاند.




