在Go语言中,是否有一种类似于使用path.Join()
处理文件路径的方法来合并URL路径的方式?
例如,可以查看合并绝对路径和相对路径以获取新的绝对路径。
当我使用path.Join("http://foo", "bar")
时,得到的结果是http:/foo/bar
。
请参见在Golang Playground中的示例。
在Go语言中,是否有一种类似于使用path.Join()
处理文件路径的方法来合并URL路径的方式?
例如,可以查看合并绝对路径和相对路径以获取新的绝对路径。
当我使用path.Join("http://foo", "bar")
时,得到的结果是http:/foo/bar
。
请参见在Golang Playground中的示例。
函数path.Join需要一个路径,而不是一个URL。Parse URL以获取路径并与该路径连接:
u, err := url.Parse("http://foo")
if err != nil { log.Fatal(err) }
u.Path = path.Join(u.Path, "bar.html")
s := u.String()
fmt.Println(s) // prints http://foo/bar.html
s, err := url.JoinPath("http://foo", "bar.html")
if err != nil { log.Fatal(err) }
fmt.Println(s) // prints http://foo/bar.html
如果您需要从基本URL解析URI引用,请使用ResolveReference。这个操作不同于简单的路径连接:参考中的绝对路径将替换整个基本路径;在连接操作之前,基本路径将被修剪回到最后一个斜杠。
base, err := url.Parse("http://foo/quux.html")
if err != nil {
log.Fatal(err)
}
ref, err := url.Parse("bar.html")
if err != nil {
log.Fatal(err)
}
u := base.ResolveReference(ref)
fmt.Println(u.String()) // prints http://foo/bar.html
net/url包中的ResolveReference()函数
对于包含文件扩展名(例如.html或.img)的相对URL路径,接受的答案将无法正常工作。 在go中,使用ResolveReference()函数是正确的连接URL路径的方法。
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("../../..//search?q=dotnet")
if err != nil {
log.Fatal(err)
}
base, err := url.Parse("http://example.com/directory/")
if err != nil {
log.Fatal(err)
}
fmt.Println(base.ResolveReference(u))
}
一个简单的方法是去掉你不想要的 /,然后连接起来。这里是一个示例函数
func JoinURL(base string, paths ...string) string {
p := path.Join(paths...)
return fmt.Sprintf("%s/%s", strings.TrimRight(base, "/"), strings.TrimLeft(p, "/"))
}
使用方法将会是
b := "http://my.domain.com/api/"
u := JoinURL(b, "/foo", "bar/", "baz")
fmt.Println(u)
这将消除检查/返回错误的需要
u, err := url.JoinPath("http://host/foo", "bar/")
要将一个URL
与另一个URL
或路径连接起来,可以使用URL.Parse()
方法:
func (u *URL) Parse(ref string) (*URL, error)
Parse parses a URL in the context of the receiver. The provided URL may be relative or absolute. Parse returns
nil
,err
on parse failure, otherwise its return value is the same asResolveReference
.
func TestURLParse(t *testing.T) {
baseURL, _ := url.Parse("http://foo/a/b/c")
url1, _ := baseURL.Parse("d/e")
require.Equal(t, "http://foo/a/b/d/e", url1.String())
url2, _ := baseURL.Parse("../d/e")
require.Equal(t, "http://foo/a/d/e", url2.String())
url3, _ := baseURL.Parse("/d/e")
require.Equal(t, "http://foo/d/e", url3.String())
}
func Join(basePath string, paths ...string) (*url.URL, error) {
u, err := url.Parse(basePath)
if err != nil {
return nil, fmt.Errorf("invalid url")
}
p2 := append([]string{u.Path}, paths...)
result := path.Join(p2...)
u.Path = result
return u, nil
}
u.String()
和ResolveReference
之间的细微差别。 - Dan Esparzapath
包在所有平台上都使用正斜杠分隔的路径。path.Join(u.Path, "bar.html")
生成的路径在所有平台上,包括Windows,都是"/foo/bar.html"
。path
包在Join
实现中确实使用正斜杠。 - Charlie Tumahaipath.Join
会剥离所有尾随斜杠(因为它在返回结果之前调用了path.Clean
),这可能会破坏具有重要尾随斜杠的URL(URL路径不一定与文件系统路径有任何关系,因此尾随斜杠可能会影响如何解释URL)-- Go 1.19解决方案明确解决了这个问题,并保留单个尾随斜杠。 - kbolino