概要
goで以下のようなURLに新たなpathを追加したい。
http://foo.bar.jp/boo/?greeting=hello
例えば /bee
を追加して以下のようにする。
http://foo.bar.jp/boo/bee?greeting=hello
結論から言うと、url.URLをコピーしてpathに対してpath.Joinをすれば良い。
詳細
url.Parseで型が *url.URL
の値が返ってくる。 url.URL
は以下のようなstruct。
type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string
RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
ForceQuery bool // append a query ('?') even if RawQuery is empty
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
goは、値の代入でコピーが発生するので単に代入をしてあげれば複製が作られる。
baseURL, _ := url.Parse(url)
copiedURL := *baseURL
URL.Path
に入っているのは単なるpathの形式を持った文字列なので path.Join()
で繋げられる。
copiedURL.Path = path.Join(copiedURL.Path, newPath)
例
はじめにのところで行おうとした処理
package main
import (
"fmt"
"net/url"
"path"
)
func main() {
baseURL, _ := url.Parse("http://foo.bar.jp/boo/?greeting=hello")
copiedURL := *baseURL
copiedURL.Path = path.Join(copiedURL.Path, "./bee")
fmt.Printf("before: %s\n", baseURL)
fmt.Printf("after : %s\n", &copiedURL)
}
以下のような出力になる
before: http://foo.bar.jp/boo/?greeting=hello
after : http://foo.bar.jp/boo/bee?greeting=hello
URL.ResolveReference()ではダメ
ところで最初はResolveReference()だけでどうにかなると思っていた。
x, _ := url.Parse("http://foo.bar.jp/boo")
// &url.URL{Scheme:"http", Opaque:"", User:(*url.Userinfo)(nil), Host:"foo.bar.jp", Path:"/boo", RawPath:"", ForceQuery:false, RawQuery:"", Fragment:""}
y, _ := url.Parse("./bee")
// &url.URL{Scheme:"", Opaque:"", User:(*url.Userinfo)(nil), Host:"", Path:"./bee", RawPath:"", ForceQuery:false, RawQuery:"", Fragment:""}
x.ResolveReference(y).String()
// "http://foo.bar.jp/bee"