使用Golang中的正则表达式从URL中提取子域名

6
在下面的代码示例中,我使用正则表达式从给定的URL中提取子域名。这个示例是可以工作的,但我认为在编译正则表达式时,尤其是在插入“virtualHost”变量时,我没有做正确。你有什么建议吗?
package main

import (
    "fmt"
    "regexp"
)

var (
    virtualHost string
    domainRegex *regexp.Regexp
)

func extractSubdomain(host string) string {
    matches := domainRegex.FindStringSubmatch(host)
    if matches != nil && len(matches) > 1 {
        return matches[1]
    }
    return ""
}

func init() {
    // virtualHost = os.GetEnv("VIRTUAL_HOST")
    virtualHost = "login.localhost:3000"

    domainRegex = regexp.MustCompile(`^(?:https?://)?([-a-z0-9]+)(?:\.` + virtualHost + `)*$`)
}

func main() {
    // host := req.host
    host := "http://acme.login.localhost:3000"

    if result := extractSubdomain(host); result != "" {
        fmt.Printf("Subdomain detected: %s\n", result)
        return
    }

    fmt.Println("No subdomain detected")
}

5
不要使用正则表达式,使用“url”包来解析URL。然后只需按句点分割即可。 - Jonathan Hall
2
只需在句点处拆分..啊是的..在提出建议之前请阅读RFC。 - ChrisG
另一种不使用正则表达式的选择是go-tld,但这并不能回答这个问题。 - ntsd
2个回答

7

url包有一个parse函数,可以解析URL。解析后的URL实例有一个方法Hostname,可以返回主机名。

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("http://login.localhost:3000")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.Hostname())
}

输出:

login.localhost

请查看: https://play.golang.com/p/3R1TPyk8qck 更新:
我的上一个回答只涉及解析主机名。之后我使用以下库来从主机名中解析域名后缀。一旦你有了这个,就可以轻松地剥离域名,只留下子域名前缀。
请查看: https://pkg.go.dev/golang.org/x/net/publicsuffix 我发现准确区分子域和主机可能有点棘手,需要先从该包获取一些帮助来识别常见后缀。例如,我们内部可能有一个来自 Kubernetes ingress 的域:
foo.bar.host.kube.domain.com.au

主机是“host”,子域名是“foo.bar”。即使使用publicsuffix库的帮助,它也不知道“kube”是内部域组件的一部分。因此,您需要添加更多自己的提示来进行匹配。

6
我不知道为什么这被标记为答案。它给出的是完整的主机名,而不是所问的子域名。这不是答案。 - ChrisG

2

这是我使用过的内容


func getSubdomain(r *http.Request) string {
    //The Host that the user queried.
    host := r.URL.Host
    host = strings.TrimSpace(host)
    //Figure out if a subdomain exists in the host given.
    hostParts := strings.Split(host, ".")

    fmt.Println("host parts",hostParts)

    lengthOfHostParts := len(hostParts)

    // scenarios
    // A. site.com  -> length : 2
    // B. www.site.com -> length : 3
    // C. www.hello.site.com -> length : 4

    if lengthOfHostParts == 4 {
        return strings.Join([]string{hostParts[1]},"") // scenario C
    }
    
    if lengthOfHostParts == 3 { // scenario B with a check
        subdomain := strings.Join([]string{hostParts[0]},"")
        
        if subdomain == "www" {
            return ""
        } else {
            return subdomain
        }
    }

    return "" // scenario A
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接