Go 言語(以下 golang)で URL をリクエストした際の最終的にリダイレクトされる先の URL が知りたい。
例えば、GitHub の Gist や Qiita では、ID だけを指定してリクエストするとコンテンツ・オーナーのユーザー名を付けた URL にリダイレクトされます。
転送前と転送後の URL
- https://gist.github.com/42f5f23053ab59ca480f480b8d01e1fd
+ https://gist.github.com/KEINOS/42f5f23053ab59ca480f480b8d01e1fd
- https://qiita.com/items/6f3bbc7f4682887c0b89
+ https://qiita.com/KEINOS/items/6f3bbc7f4682887c0b89
cURL によるリクエスト例
$ # リダイレクト先に /KEINOS が付加されている
$ # Gist@GitHub
$ curl -Ls -o /dev/null -w %{url_effective} https://gist.github.com/42f5f23053ab59ca480f480b8d01e1fd
https://gist.github.com/KEINOS/42f5f23053ab59ca480f480b8d01e1fd
$ # Items@Qiita
$ curl -Ls -o /dev/null -w %{url_effective} https://qiita.com/items/6f3bbc7f4682887c0b89
https://qiita.com/KEINOS/items/6f3bbc7f4682887c0b89
コンテンツもサルことながら、単純に golang で、この URL を取得したいのです。
「"golang" リダイレクト 最終 URL 取得」でググっても、ソースが動かなかったり、HEAD
メソッドを受け付けてないエラーが出たりしたので、自分のググラビリティとして。
TL; DR (今北産業)
import (
"net/http"
"time"
)
// FindRedirectURL はリダイレクトされた最終的な URL を返します。15 秒経過してもレスポンスが
// ない場合はタイムアウトでエラーを返します。
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
}
ヘッダー情報だけで判断したい場合(軽量版)
import (
"net/http"
"time"
)
// FindRedirectURL はリダイレクトされた最終的な URL を返します。15 秒経過してもレスポンスが
// ない場合はタイムアウトでエラーを返します。
func FindRedirectURL(url string) (string, error) {
client := &http.Client{
Timeout: 15 * time.Second,
}
//resp, err := client.Get(url)
resp, err := client.Head(url)
if err != nil {
return "", err
}
finalURL := resp.Request.URL.String()
return finalURL, nil
}
example.go
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func FindRedirectURL(url string) (string, error) {
client := &http.Client{
Timeout: 15 * time.Second,
}
resp, err := client.Head(url)
if err != nil {
return "", err
}
finalURL := resp.Request.URL.String()
return finalURL, nil
}
func main() {
urlOriginal := "https://gist.github.com/42f5f23053ab59ca480f480b8d01e1fd"
fmt.Println("Original:", urlOriginal)
urlRedirect, err := FindRedirectURL(urlOriginal)
if err != nil {
log.Fatal(err)
}
fmt.Println("Redirect:", urlRedirect)
// Output:
// Original: https://gist.github.com/42f5f23053ab59ca480f480b8d01e1fd
// Redirect: https://gist.github.com/KEINOS/42f5f23053ab59ca480f480b8d01e1fd
}
- オンラインで動作を見る @ paiza.IO
検証環境
$ date
2023年 5月15日 月曜日 12時26分29秒 JST
$ go version
go version go1.20.4 darwin/amd64
$ sw_vers
ProductName: macOS
ProductVersion: 12.6.5
BuildVersion: 21G531
- 参考文献:
- Overview | http | net @ pkg.go.dev
- 「Go net/http タイムアウト」の完全ガイド @ blog.cloudflare.com
- In golang, how to determine the final URL after a series of redirects? @ StackOverflow
- Get final URL after curl is redirected @ StackOverflow