Как сделать редирект по URL на localhost
Что проверяют
Знаете ли вы, как устроен редирект в HTTP: сервер лишь отдаёт код 3xx и заголовок Location, а переходит клиент. Отсюда главный подвох с localhost и уточнение, чем редирект отличается от проксирования.
Как отвечать
В стандартной библиотеке это одна функция:
mux := http.NewServeMux()
mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "http://localhost:8081"+r.URL.RequestURI(), http.StatusFound)
})Шаблон "/{$}" из маршрутизатора Go 1.22+ совпадает только с корнем, а обычный "/" ловит все пути. Для постоянного правила без логики есть http.RedirectHandler(url, code).
Дальше выбор кода:
- 301 и 308: постоянный редирект, браузер кеширует его надолго. На локальной разработке такой кеш потом мешает, пока его не очистите;
- 302 и 303: временный. Браузеры после 302 превращают POST в GET, 303 делает это явно;
- 307: временный с сохранением метода и тела, нужен для API и форм.
Главное про localhost: адрес в Location разрешает клиент. Если сервер в проде отдаёт Location: http://localhost:8080/..., браузер пользователя пойдёт на его собственный компьютер. Такой адрес уместен, только когда клиент и сервер на одной машине, в остальных случаях берите хост из конфигурации или относительный путь.
Если нужно, чтобы запрос обработал сервис на localhost, а адрес в браузере не менялся, это не редирект, а httputil.NewSingleHostReverseProxy.
Где спотыкаются
Забывают return после http.Redirect. Хендлер выполняется дальше, дописывает в ответ лишнее, а повторный WriteHeader даёт в логе superfluous response.WriteHeader call.
Ставят 301 «на время». Браузер запоминает его, и после исправления кода пользователи ещё долго уходят по старому адресу.
Берут адрес назначения из параметра запроса без проверки. Это открытый редирект, которым пользуются фишинговые ссылки. Родственная ошибка: редирект с localhost на 127.0.0.1 теряет cookies, потому что для браузера это разные хосты.