10 хв читанняІнженерія

Цикл редиректів: як знайти і виправити ERR_TOO_MANY_REDIRECTS

Цикл редиректів гойдає браузер між URL-адресами, доки той не здається. Простежте ланцюжок редиректів однією командою, визначте правило, яке суперечить іншому, і виправте це назавжди.

Marius Voß
DevRel · edge infra
Цикл редиректів у вигляді двох URL-адрес, що вказують одна на одну, доки лічильник стрибків браузера не вичерпується і не повертає ERR_TOO_MANY_REDIRECTS

Цикл редиректів - це ланцюжок HTTP-редиректів, який ніколи не приземляється: URL-адреса A відправляє браузер на URL-адресу B, B відправляє його назад на A, і приблизно після двадцяти стрибків браузер припиняє спроби й показує ERR_TOO_MANY_REDIRECTS. На сторінці призначення нічого не зламано. Два правила просто сперечаються про те, де має бути ця URL-адреса, і кожне з них постійно скасовує дію іншого.

Циклічний редирект - одна з небагатьох веб-помилок, яка сама називає свою причину, якщо дивитися в правильне місце. Не браузер, не сторінка помилки і точно не кеш: ланцюжок редиректів. Кожен стрибок несе заголовок Location, і дві адреси, які постійно повторюються, - це два правила, які потрібно узгодити. Цей гайд проходить діагностику однією командою, причини майже кожного циклу редиректів, який мені доводилося розплутувати, і виправлення, яке тихцем не створює другий цикл десь-інде. Якщо сама родина редиректів досі незрозуміла, типи URL-редиректів - це карта; тут - версія для усунення несправностей.

Що насправді означає ERR_TOO_MANY_REDIRECTS

Браузери переходять за редиректами від вашого імені, але не вічно. Кожен клієнт має бюджет стрибків і кидає запит, коли він вичерпується: Chrome зупиняється на 20 і не дає це змінити, Firefox постачається з тим самим значенням за замовчуванням під назвою network.http.redirection-limit, а curl дозволяє 50, перш ніж поскаржитися. Стандарт залишає число відкритим. RFC 9110 каже лише, що клієнт має виявляти циклічні редиректи й втручатися в них, що є ввічливим способом специфікації сказати, що кожному браузеру потрібен запобіжник.

Ця відмінність важлива для діагностики, бо помилка взагалі не доводить існування циклу. Ланцюжок із двадцяти одного різного стрибка без повторів викликає точно те саме повідомлення, що й дві URL-адреси, які вічно перекидають м'яч одна одній. Виправляти варто обидва випадки, але лише в одному з них є пара адрес, які потрібно узгодити. Довідник MDN з редиректів охоплює обидві форми, а практична різниця стає видною тієї самої секунди, коли ви друкуєте ланцюжок.

Цикл редиректів між HTTPS URL-адресою і HTTP URL-адресою, коли лічильник стрибків браузера досягає межі й повертає ERR_TOO_MANY_REDIRECTS

Ще одна річ, яку приховує сторінка помилки: постійний редирект кешується браузером. Якщо цикл побудований із відповідей 301, відвідувачі й далі циклитимуться локально навіть після виправлення сервера, доки цей запис у кеші не спливе або вони самі його не очистять. Саме цей факт - причина, чому я тестую зміни редиректів через 302 і підвищую до 301 лише тоді, коли ланцюжок вже правильний; звичку, яку повністю обґрунтовує 301 проти 302 редиректів.

Простежте ланцюжок редиректів однією командою

Пропустіть браузер. Найшвидший спосіб прочитати будь-який цикл редиректів - термінал, бо curl друкує кожен стрибок, а не згортає їх в одну сторінку помилки:

curl -sIL https://example.com | grep -E '^HTTP|^[Ll]ocation'

Ви отримуєте рядок статусу і заголовок Location для кожного стрибка, по порядку. Прочитайте це згори донизу, і виявиться один із трьох шаблонів. Дві URL-адреси, що чергуються, означають справжній цикл, і ця пара називає обидва правила-порушники. Довгий марш різних URL-адрес означає ланцюжок, який хтось нашаровував роками, і кожен стрибок сам собою легітимний. А ланцюжок, що добре резолвиться в терміналі, але все одно ламається в браузері, означає, що цикл спричинений куками, бо curl за замовчуванням не надсилає жодних кук.

Останній випадок заслуговує на окрему перевірку, бо саме він змушує людей півдня звинувачувати свій DNS:

curl -sIL -c jar.txt -b jar.txt https://example.com/account | grep -E '^HTTP|^[Ll]ocation'

З підключеним файлом кук цикл входу або згоди відтворюється прямо в командному рядку, де реально видно, який ендпоінт постійно встановлює, а тоді відхиляє сесію. У браузері еквівалентний вигляд - панель Network з увімкненим "Preserve log", яка не дає стерти попередні стрибки під час навігації сторінки. Якщо вам узагалі не хочеться відкривати термінал, наш перевіряч посилань простежує ланцюжок прямо в браузері і друкує код статусу на кожному стрибку.

Причини майже кожного циклу редиректів

Щойно ланцюжок стає видимим, причина зазвичай одна з невеликої жменьки. Пара URL-адрес, що повторюється, підказує, на який рівень дивитися: схема, що перемикається туди-сюди, вказує на завершення TLS, ім'я хоста, що перемикається, вказує на правило канонічного хоста, а шлях, який то отримує, то втрачає слеш, вказує на порядок правил переписування.

Правила https за проксі, що завершує TLS

Це найпоширеніший нескінченний редирект у сучасному вебі, і він з'явився в ту мить, коли проксі почали завершувати TLS перед origin-серверами. Проксі приймає HTTPS-запит від відвідувача, а тоді звертається до вашого origin через звичайний HTTP. Ваш origin бачить незахищений запит, робить те, що ви йому наказали, і редиректить на HTTPS. Проксі віддає цей редирект, отримує новий запит, знову звертається до origin через HTTP, і так по колу. Cloudflare документує саме цей збій під назвою свого гнучкого режиму шифрування, і в кожного іншого проксі є та сама пастка під іншою назвою.

Є два чисті виправлення. Перемкніть проксі на повний режим шифрування, щоб він спілкувався з вашим origin через TLS - це правильна відповідь майже в кожному випадку. Або, якщо стрибок до origin справді має лишатися незахищеним, зробіть так, щоб правило origin читало заголовок X-Forwarded-Proto, а не сире з'єднання, щоб воно перестало редиректити запити, які вже були захищені на межі мережі.

www і apex сперечаються, який хост має перемогти

Одне правило канонічного хоста - це нормально. Два таких правила, написані в різний час різними людьми, - це цикл. Класичний варіант: конфігурація сервера відправляє apex на www, поки конфігурація застосунку відправляє www назад на apex, і обидва впевнені, що мають рацію. Ви побачите це миттєво в ланцюжку: example.com на www.example.com на example.com, і так без кінця.

Оберіть один хост, застосовуйте його рівно в одному місці й видаліть інше правило, замість того щоб намагатися їх узгодити. Те саме стосується правила зі слешем наприкінці або переписування в нижній регістр: коли два правила нормалізують ту саму URL-адресу в протилежних напрямках, ви отримуєте цикл редиректів, навіть якщо кожне правило окремо цілком розсудливе.

Налаштування URL-адреси в CMS чи застосунку, яке більше не відповідає дійсності

Більшість застосунків зберігають власну канонічну адресу, і це поле - редирект-правило з дружньою назвою. Змініть домен, перенесіть на нове середовище або відновіть знімок бази даних з іншого хоста, і застосунок почне редиректити кожен запит на адресу, яка редиректить назад. Оскільки це налаштування живе в базі даних, а не в конфігурації вашого вебсервера, воно переживає аудит конфігурації, який ви щойно провели, і саме тому його так важко знайти.

Ознака - ланцюжок, який залишає ваше поточне ім'я хоста і ніколи до нього не повертається. Виправте збережену адресу на домен, який ви насправді обслуговуєте, а тоді очистіть будь-який кеш застосунку чи сторінок, що зафіксував неправильну адресу.

Цикли кук і сесій, що зачіпають лише авторизованих користувачів

Тут правила ні до чого, а проблема - у стані. Шлюз редиректить неавторизованих відвідувачів на сторінку входу, сторінка входу редиректить авторизованих назад, а кука сесії, яку не можна прочитати на цільовому домені, залишає обидві сторони впевненими, що обробляти це має інша. Банери згоди спричиняють ту саму форму, коли редирект, що встановлює куку згоди, сам заблокований.

Ознака та сама, що й у попередньому розділі: чисте приватне вікно працює, або curl без файлу кук резолвиться нормально. Перевірте домен і область Path куки, її атрибути Secure і SameSite відповідно до схеми, яку ви насправді обслуговуєте, і чи не встановлюється вона на apex, поки читається на www.

Що повторюється в ланцюжкуЙмовірна причинаЩо змінити першим
http на https і назадПроксі завершує TLS, origin наполягаєПовний режим шифрування або довіра XFP
Apex на www і назадДва правила канонічного хостаВидалити одне, лишити єдине правило
Шлях то отримує, то втрачає слешПравила переписування в неправильному порядкуНормалізувати один раз, до будь-якої маршрутизації
Залишає ваш хост і не повертаєтьсяЗбережена адреса сайту застарілаВиправити URL-налаштування застосунку, очистити кеш

Цикли редиректів рідко залишаються загадковими, щойно ланцюжок опиняється на екрані, але вони цілком можуть з'їсти півдня, якщо здогадуватися замість того, щоб простежувати. Якщо ви хочете володіти рівнем редиректів, а не сперечатися з ним, безкоштовний план Elido дає вам посилання, чиє призначення - єдине збережене значення, яке можна перенаправити, з логуванням кожного стрибка.

Виправте це, не створивши другий цикл

Саме виправлення коротке, і порядок дій важливіший за синтаксис. Змініть одне правило, а тоді простежте знову. Змінити три й перезавантажити не скаже вам нічого про те, яке саме мало значення, і я бачив, як команда витратила годину саме так - на цикл, спричинений правилом, яке вони вже виправили з першої спроби.

  1. Приберіть або інвертуйте рівно одне з двох правил, названих ланцюжком, щоб запит міг дістатися 200 за один стрибок.
  2. Запустіть трасування curl -sIL знову і переконайтеся, що тепер ланцюжок - щонайбільше один редирект, без повторюваного імені хоста.
  3. Очистіть кеш браузера або протестуйте в приватному вікні, бо будь-який 301, який ви віддавали раніше, досі закешований локально і симулюватиме збій, якого вже не існує.
  4. Лише тоді підвищуйте тимчасові редиректи до постійних, коли форма ланцюжка вже усталена.

Наприкінці цього списку чекають дві пастки. Одна - HSTS: щойно хост надіслав заголовок Strict-Transport-Security, браузери самі підвищують кожен запит до HTTPS, тож правило origin, яке також примусово вмикає HTTPS, стає зайвим і може перетворити помилку налаштування проксі на цикл, який неможливо відтворити без очищення запису HSTS. Друга пастка - кешування перед циклом. CDN, що закешував 301, охоче продовжуватиме його віддавати навіть після того, як origin перестане його надсилати, тому очищення кешу має бути частиною виправлення, а не наступним кроком після нього. Довгі ланцюжки, які ніколи не циклюються, теж варто скорочувати в тому самому підході: кожен зайвий стрибок - це ще один шанс загубити рядок запиту, а саме так губляться UTM-параметри в GA4, і це частково пояснює, чому короткі посилання не мусять шкодити SEO, доки вони лишаються глибиною в один стрибок.

Вигляд ланцюжка редиректів до і після: ланцюжок із чотирьох стрибків, що циклиться між хостами, і той самий запит, розв'язаний єдиним канонічним редиректом

Коли цикл трапляється на короткому посиланні

Короткі посилання додають ще одне місце, де може сформуватися цикл, і це не сам редирект скорочувача. Коротке посилання - це єдиний збережений стрибок: слаг на вході, призначення на виході. Цикл з'являється, коли призначення вказує назад, і трапляється це частіше, ніж здається. Хтось редагує посилання кампанії, щоб воно вело на цільову сторінку, у цільової сторінки є старе правило, що редиректить на коротку URL-адресу, бо саме вона була канонічною адресою для поширення минулого кварталу, і тепер вони обидва відскакують одне від одного. Обидва стрибки поводяться точно так, як налаштовано.

У тому самому ланцюжку трапляються ще два варіанти. Один - пара коротких посилань, що вказують одне на одного після масового редагування, зазвичай через імпорт з таблиці, де в колонці призначення були короткі URL-адреси замість кінцевих. Другий - кастомний домен, який досі резолвиться на хост, що редиректить назад на скорочувач, а це радше залишок DNS, ніж проблема посилання, і кастомні домени для коротких посилань розглядає, якими мають бути записи. У всіх трьох випадках виправлення - вказати в призначенні кінцеву сторінку, а не ще один редирект, і зробити це можна, не торкаючись нічого вже надрукованого чи опублікованого.

Оскільки призначення збережене, а не закладене прямо в URL-адресу, ніщо з цього не вимагає передруку. Це весь аргумент на користь керованих посилань, а коротке посилання не працює - ширший гайд із діагностики на випадок, коли симптом не є саме циклом.

Не дайте наступному циклу потрапити в реліз

Цикли редиректів - це баг дрейфу конфігурації, тож надійні виправлення - нудні. Тримайте рішення про канонічний хост в одному місці й одразу трактуйте будь-яке друге правило, що торкається схеми чи імені хоста, як баг. Простежуйте нові редиректи через curl -sIL до того, як про них оголосити, а не після того, як хтось повідомить про порожню сторінку. Якщо посилання впливають на дохід, поставте на них перевірку: заплановане трасування, яке падає, коли ланцюжок виростає понад один стрибок, ловить дрейф задовго до того, як це зробить клієнт, а моніторинг редиректів посилань показує, як це виглядає, підключене до справжніх сповіщень.

Ширша звичка - ставитися до призначень як до даних, які можна аудитувати. Запобігання протуханню посилань розглядає ту саму дисципліну для посилань, які тихо перестають резолвитися, і в будь-якому разі це та сама щотижнева перевірка. Чесно кажучи, більшість циклів, які я бачив, випустили в реліз двоє компетентних людей, кожен з яких виправив ту саму проблему на іншому рівні, з різницею в місяць. Запишіть правило один раз - і цикл стає неможливим.

Читайте серію ключових матеріалів

Цей матеріал належить до інженерного кластера. Про форму самого шляху редиректу розповідає досягнення p95 нижче 15 мс для редиректів - скільки коштує один добре поведений стрибок, а типи URL-редиректів розглядає, який код статусу де застосовувати, перш ніж ви почнете нашаровувати правила.

Ще в блозі

Поширені запитання

Що означає ERR_TOO_MANY_REDIRECTS?

Це означає, що браузер переходив від одного редиректу до іншого, так і не дістався справжньої сторінки, вичерпав ліміт стрибків і зупинився. Сама сторінка зазвичай справна; два правила редиректу сперечаються про те, де насправді має бути URL-адреса, тож кожне скасовує дію іншого. Chrome показує ERR_TOO_MANY_REDIRECTS, Firefox повідомляє, що сторінка неправильно перенаправляє, а Safari повідомляє, що сталося забагато редиректів.

Як виправити ERR_TOO_MANY_REDIRECTS?

Спершу простежте ланцюжок, а тоді приберіть одне з двох правил, які борються за URL-адресу. Запустіть curl -sIL на адресу й прочитайте кожен заголовок Location: пара URL-адрес, яка повторюється, підказує, яке правило видалити або інвертувати. Звичні винуватці - правило HTTPS, що працює за проксі, який завершує TLS, правило www, накладене поверх іншого правила www, і налаштування адреси сайту, яке більше не відповідає домену, що обслуговується.

Скільки редиректів пройде браузер, перш ніж здатися?

Приблизно двадцять, залежно від браузера. Chrome зупиняється після 20 стрибків, і цей ліміт не налаштовується, Firefox відкриває ту саму межу як network.http.redirection-limit зі значенням за замовчуванням 20, а curl проходить до 50, якщо не змінити --max-redirs. Специфікація не встановлює числа: RFC 9110 лише каже, що клієнт має виявляти циклічні редиректи й втручатися в них, тож кожен клієнт обирає власну межу.

Чи виправляє очищення кук цикл редиректів?

Іноді, і це вже підказка. Якщо приватне вікно завантажує сторінку без проблем, цикл спричинений застарілою кукою сесії чи згоди, а не правилами вашого сервера, і її очищення - реальне виправлення для цього відвідувача. Якщо цикл трапляється і в свіжому приватному вікні, куки ні до чого, а проблема - у правилі редиректу, налаштуванні проксі або полі URL-адреси в CMS.

Чому мій сайт почав циклитися після ввімкнення HTTPS або CDN-проксі?

Тому що тепер обидва рівні наполягають на HTTPS, хоча один із них звертається до вашого origin через звичайний HTTP. Проксі запитує origin на порту 80, правило origin відправляє його назад на HTTPS, проксі відповідає на цей запит так само, і цикл не закінчується ніколи. Перемкніть режим шифрування проксі на повний, щоб він звертався до origin через TLS, або зробіть так, щоб ваше правило довіряло заголовку X-Forwarded-Proto, а не сирому з'єднанню.

Чи може коротке посилання спричинити цикл редиректів?

Так, коли призначення вказує назад на коротке посилання, або коли два посилання вказують одне на одне. Найпоширеніший варіант - редагування посилання так, що воно веде на сторінку, яка сама редиректить на коротку URL-адресу, і це переживає кожне оновлення браузера, бо обидва стрибки працюють точно так, як налаштовано. Вкажіть у призначенні кінцеву сторінку, а не ще один редирект, і цикл зникає без потреби щось передруковувати.

Спробуйте Elido

Вставте URL - отримайте коротке посилання

Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.

Безкоштовно, без реєстрації · 2 на день

Спробуйте Elido

URL-скорочувач із хостингом у ЄС: власні домени, глибока аналітика, відкритий API. Безкоштовний тариф - без кредитної картки.

Теги
redirect loop
err_too_many_redirects
too many redirects
redirect chain
infinite redirect
301 redirect loop

Читати далі