Отслеживание HTTP-перенаправлений в Golang

Отслеживание HTTP-перенаправлений в Golang
Сегодня мы рассмотрим как обрабатывать HTTP-запросы в Go и предотвращать автоматические переходы на 301, 302 и подобные перенаправления. Это может понадобиться для раскрытия сокращённых ссылок из twitter, buffer, bit.ly или маркетинговых рассылок. Или для проверки ваших утилит для генерации таких ссылок 😉 Демо-версию можно посмотреть тут.

Внимание: для дальнейшей работы понадобится go не старше версии 1.7, иначе вам будут недоступны некоторые важные функции пакета net/http. Узнать версию Go можно командой go version в терминале. Ответ должен быть примерно таким: go version go1.7.3 linux/amd64.

Создание HTTP запросов в Go

Посмотрим как можно создать простой HTTP запрос в Go и прочитать его код состояния:

// file: http-request.go
package main

import(
"fmt"
"net/http"
)

func main(){
resp, err := http.Get("http://www.jonathanmh.com/")

if err != nil {
fmt.Println(err)
}

fmt.Println("StatusCode:", resp.StatusCode)
fmt.Println(resp.Request.URL)
}

Ответ:

StatusCode: 200
https://jonathanmh.com/

Обратите внимание, что в resp.Request.URL мы получили совсем не тот адрес, что передали методу Get. Это произошло потому, что я перенаправляю пользователей с адреса www.jonathanmh.com на jonathanmh.com. Go делает всё как положено и просто следует правилам. В большинстве случаев такое поведение мы и ожидаем, но только не в том, случае, когда хотим сделать что-то вроде утилиты для проверки перенаправлений! В этом случае мы хотим знать каждый шаг перенаправления и код состояния каждого запроса.

Создание HTTP запросов в Go без следования редиректам

Для того, чтобы не следовать автоматическим перенаправлениям, создадим свой экземпляр http.Client с методом проверки CheckRedirect. Это поможет нам возвращать код состояния и адрес до перенаправления.

// file: http-nofollow-request.go
package main

import(
"fmt"
"net/http"
)

func main(){
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
} }

resp, err := client.Get("http://www.jonathanmh.com")

if err != nil {
fmt.Println(err)
}

fmt.Println("StatusCode:", resp.StatusCode)
fmt.Println(resp.Request.URL)
}

Ответ:

StatusCode: 301
http://www.jonathanmh.com

Супер! Мы пока не получили URL перенаправления, но у нас есть код состояния, что уже неплохо. Итак, продолжим.

Перебор HTTP-перенаправлений в Go

Теперь рассмотрим как можно обойти все перенаправления для получения конечного адреса. Сперва нам нужно задать лимит для запросов (иначе нас смогут отправить в бесконечную петлю перенаправлений) и добавить условие окончания перебора.

Будем считать, что получив код состояния 200, наш обход будет закончен и мы получим финальный адрес.

// file: http-redir-loop.go
package main

import(
"fmt"
"net/http"
)

func main(){
myURL := "http://www.jonathanmh.com"
nextURL := myURL
var i int
for i < 100 { client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } } resp, err := client.Get(nextURL) if err != nil { fmt.Println(err) } fmt.Println("StatusCode:", resp.StatusCode) fmt.Println(resp.Request.URL) if resp.StatusCode == 200 { fmt.Println("Done!") break } else { nextURL = resp.Header.Get("Location") } } }

Ответ:

StatusCode: 301

I’m JonathanMH


StatusCode: 301

I’m JonathanMH


StatusCode: 200

I’m JonathanMH


Done!

Этот код практически повторяет предыдущий пример, однако здесь мы добавили пару переменных, myURL и nextURL. И в конце цикла, если состояние не 200 - OK, мы присваиваем переменной nextURL значение resp.Header.Get("Location") - это HTTP заголовок цели перенаправления. Вы можете отслеживать эти заголовки на вкладке Сеть (Network) в Инструментах разработчика (Developer Tools) в Chrome или Firefox, поставив галочку Preserve Log.

Вот и всё! Теперь вы знаете, как делать несколько прикольных штук с net/http в Go. Теперь вы можете обернуть этот код в http API, запустить программу на сервере, ну и, конечно же, добавить ей простенький интерфейс, вроде того, как я сделал тут.

Для дальнейшего изучения

Одной статьёй не охватить всего, поэтому рекомендую почитать следующие материалы по теме:

Буду рад, если поделитесь мыслями по поводу материала и если он был полезен вам!

От переводчика: вы можете прокомментировать как оригинальный пост, так и перевод, но автор будет очень рад комментариям в своём блоге 🙂

Источник: "Tracing or Preventing HTTP Redirects in Golang"

1 thought on “Отслеживание HTTP-перенаправлений в Golang

Leave a Comment