英文:
Combine URL paths with path.Join()
问题
在Go语言中,是否有一种类似于使用path.Join()
函数组合文件路径的方式来组合URL路径的方法?
例如,可以参考https://stackoverflow.com/q/13078314/772000。
当我使用path.Join("http://foo", "bar")
时,得到的结果是http:/foo/bar
。
可以在Golang Playground中查看示例。
英文:
Is there a way in Go to combine URL paths similarly as we can do with filepaths using path.Join()
?
For example see e.g. https://stackoverflow.com/q/13078314/772000.
When I use path.Join("http://foo", "bar")
, I get http:/foo/bar
.
See in Golang Playground.
答案1
得分: 154
函数path.Join期望一个路径,而不是一个URL。解析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) // 输出 http://foo/bar.html
在Go 1.19或更高版本中,可以使用url.JoinPath函数:
s, err := url.JoinPath("http://foo", "bar.html")
if err != nil { log.Fatal(err) }
fmt.Println(s) // 输出 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()) // 输出 http://foo/bar.html
请注意,基本URL中的quux.html在解析后的URL中不出现。
英文:
The function path.Join expects a path, not a URL. Parse the URL to get a path and join with that path:
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
Use the url.JoinPath function in Go 1.19 or later:
s, err := url.JoinPath("http://foo", "bar.html")
if err != nil { log.Fatal(err) }
fmt.Println(s) // prints http://foo/bar.html
Use ResolveReference if you are resolving a URI reference from a base URL. This operation is different from a simple path join: an absolute path in the reference replaces the entire base path; the base path is trimmed back to the last slash before the join operation.
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
Notice how quux.html in the base URL does not appear in the resolved URL.
答案2
得分: 41
接受的答案对于包含.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))
}
英文:
ResolveReference() in net/url package
The accepted answer will not work for relative url paths containing file endings like .html or .img. The ResolveReference() function is the correct way to join url paths in go.
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))
}
答案3
得分: 10
一个简单的方法是修剪掉你不想要的斜杠并连接起来。这是一个示例函数:
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)
这样就不需要检查/返回错误了。
英文:
A simple approach to this would be to trim the /'s you don't want and join. Here is an example func
func JoinURL(base string, paths ...string) string {
p := path.Join(paths...)
return fmt.Sprintf("%s/%s", strings.TrimRight(base, "/"), strings.TrimLeft(p, "/"))
}
Usage would be
b := "http://my.domain.com/api/"
u := JoinURL(b, "/foo", "bar/", "baz")
fmt.Println(u)
This removes the need for checking/returning errors
答案4
得分: 8
在1.19版本中,标准库将会有一个非常巧妙地解决这个问题的新函数。
u, err := url.JoinPath("http://host/foo", "bar/")
https://go.dev/play/p/g422ockBq0q?v=gotip
英文:
In 1.19 there will be a new function in the standard library that solves this very neatly.
u, err := url.JoinPath("http://host/foo", "bar/")
答案5
得分: 7
要将一个URL
与另一个URL
或路径连接起来,可以使用URL.Parse()
方法:
func (u *URL) Parse(ref string) (*URL, error)
Parse
方法在接收器的上下文中解析URL。提供的URL可以是相对路径或绝对路径。如果解析失败,Parse
返回nil
和err
,否则返回值与ResolveReference
相同。
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())
}
英文:
To join a URL
with another URL
or a path, there is 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 as ResolveReference
.
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())
}
答案6
得分: 0
我写了这个实用函数,适用于我的需求:
func Join(basePath string, paths ...string) (*url.URL, error) {
u, err := url.Parse(basePath)
if err != nil {
return nil, fmt.Errorf("无效的URL")
}
p2 := append([]string{u.Path}, paths...)
result := path.Join(p2...)
u.Path = result
return u, nil
}
你可以在这里查看代码示例:https://play.golang.org/p/-QNVvyzacMM
英文:
I wrote this utility function that works for my purposes:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论