Aaron Johnson
Aaron Johnson

Reputation: 815

In golang, how to determine the final URL after a series of redirects?

So, I'm using the net/http package. I'm GETting a URL that I know for certain is redirecting. It may even redirect a couple of times before landing on the final URL. Redirection is handled automatically behind the scenes.

Is there an easy way to figure out what the final URL was without a hackish workaround that involves setting the CheckRedirect field on a http.Client object?

I guess I should mention that I think I came up with a workaround, but it's kind of hackish, as it involves using a global variable and setting the CheckRedirect field on a custom http.Client.

There's got to be a cleaner way to do it. I'm hoping for something like this:

package main

import (
  "fmt"
  "log"
  "net/http"
)

func main() {
  // Try to GET some URL that redirects.  Could be 5 or 6 unseen redirections here.
  resp, err := http.Get("http://some-server.com/a/url/that/redirects.html")
  if err != nil {
    log.Fatalf("http.Get => %v", err.Error())
  }

  // Find out what URL we ended up at
  finalURL := magicFunctionThatTellsMeTheFinalURL(resp)

  fmt.Printf("The URL you ended up at is: %v", finalURL)
}

Upvotes: 33

Views: 18278

Answers (3)

KEINOS
KEINOS

Reputation: 109

Here's my two cents with time-out over the best answer. (Tested: Go v1.20.4, darwin/amd64)

import (
    "net/http"
    "time"
)

// FindRedirectURL returns the final URL after redirection. It will
// error with time-out after 15 seconds.
func FindRedirectURL(url string) (string, error) {
    client := &http.Client{
        Timeout: 15 * time.Second,
    }

    resp, err := client.Get(url)
    if err != nil {
        return "", err
    }

    finalURL := resp.Request.URL.String()

    return finalURL, nil
}

Upvotes: 0

Airenas
Airenas

Reputation: 425

I would add a note that http.Head method should be enough to retrieve the final URL. Theoretically it should be faster comparing to http.Get as a server is expected to send back just a header:

resp, err := http.Head("http://stackoverflow.com/q/16784419/727643")
...
finalURL := resp.Request.URL.String()
...

Upvotes: 4

Stephen Weinberg
Stephen Weinberg

Reputation: 53398

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    resp, err := http.Get("http://stackoverflow.com/q/16784419/727643")
    if err != nil {
        log.Fatalf("http.Get => %v", err.Error())
    }

    // Your magic function. The Request in the Response is the last URL the
    // client tried to access.
    finalURL := resp.Request.URL.String()

    fmt.Printf("The URL you ended up at is: %v\n", finalURL)
}

Output:

The URL you ended up at is: http://stackoverflow.com/questions/16784419/in-golang-how-to-determine-the-final-url-after-a-series-of-redirects

Upvotes: 89

Related Questions