使用path.Join()函数合并URL路径。

huangapple go评论94阅读模式
英文:

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

ResolveReference()在net/url包中

接受的答案对于包含.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/")

https://go.dev/play/p/g422ockBq0q?v=gotip

答案5

得分: 7

要将一个URL与另一个URL或路径连接起来,可以使用URL.Parse()方法:

func (u *URL) Parse(ref string) (*URL, error)

Parse方法在接收器的上下文中解析URL。提供的URL可以是相对路径绝对路径。如果解析失败,Parse返回nilerr,否则返回值与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
}

https://play.golang.org/p/-QNVvyzacMM

huangapple
  • 本文由 发表于 2016年1月8日 09:16:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/34668012.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定