How Can I Make the Go HTTP Client NOT Follow Redirects Automatically?

Issue

I’m currently writing some software in Go that interacts with a REST API. The REST API endpoint I’m trying to query returns an HTTP 302 redirect along with an HTTP Location header, pointing to a resource URI.

I’m trying to use my Go script to grab the HTTP Location header for later processing.

Here’s what I’m currently doing to achieve this functionality:

package main

import (
        "errors"
        "fmt"
        "io/ioutil"
        "net/http"
)

var BASE_URL = "https://api.example.com/v1"
var STORMPATH_API_KEY_ID = "xxx"
var STORMPATH_API_KEY_SECRET = "xxx"

func noRedirect(req *http.Request, via []*http.Request) error {
        return errors.New("Don't redirect!")
}

func main() {

        client := &http.Client{
            CheckRedirect: noRedirect
        }
        req, err := http.NewRequest("GET", BASE_URL+"/tenants/current", nil)
        req.SetBasicAuth(EXAMPLE_API_KEY_ID, EXAMPLE_API_KEY_SECRET)

        resp, err := client.Do(req)

        // If we get here, it means one of two things: either this http request
        // actually failed, or we got an http redirect response, and should process it.
        if err != nil {
            if resp.StatusCode == 302 {
                fmt.Println("got redirect")
            } else {
                panic("HTTP request failed.")
            }
        }
        defer resp.Body.Close()

}

This feels like a bit of a hack to me. By overriding the http.Client‘s CheckRedirect function, I’m essentially forced to treat HTTP redirects like errors (which they aren’t).

I’ve seen several other places suggesting to use an HTTP transport instead of an HTTP client — but I’m not sure how to make this work since I need the HTTP Client as I need to use HTTP Basic Auth to communicate with this REST API.

Can any of you tell me a way to make HTTP requests with Basic Authentication — while not following redirects — that doesn’t involve throwing errors and error handling?

Solution

There’s a much simpler solution right now:

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

This way, the http package automatically knows: “Ah, I shouldn’t follow any redirects”, but does not throw any error. From the comment in the source code:

As a special case, if CheckRedirect returns ErrUseLastResponse,
then the most recent response is returned with its body
unclosed, along with a nil error.

Answered By – Etienne Bruines

Answer Checked By – Dawn Plyler (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.