Отслеживание 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
http://www.jonathanmh.com
StatusCode: 301
http://jonathanmh.com/
StatusCode: 200
https://jonathanmh.com/
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 комментарий
AktionAction
Спасибо за статью.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.