You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go语言中检查主机名/URL.Hostname是否为有效域名?匹配.NET的URI.CheckHostName

Nice question! Replicating .NET's URI.CheckHostName exact behavior in Go requires implementing its specific validation rules, since Go's standard library doesn't include a direct equivalent out of the box. Let's break this down step by step, including how to validate a URL's Hostname() value.

Understanding .NET's URI.CheckHostName Behavior

First, let's recap what .NET's method does: it inspects a hostname and returns a UriHostNameType enum with these possible values:

  • Invalid: The hostname doesn't meet any valid format rules
  • IPv4: The hostname is a valid IPv4 address
  • IPv6: The hostname is a valid IPv6 address
  • Dns: The hostname is a valid DNS domain (including internationalized domain names, or IDNs)

Our goal is to mirror this exact logic in Go.

Implementing the Equivalent in Go

We'll start by defining an enum matching .NET's type, then build a validation function that covers all the rules.

Step 1: Define the Hostname Type Enum

package main

import (
    "net"
    "strings"
    "golang.org/x/net/idna"
)

// UriHostNameType matches .NET's UriHostNameType enum values
type UriHostNameType int

const (
    UriHostNameTypeInvalid UriHostNameType = iota
    UriHostNameTypeIPv4
    UriHostNameTypeIPv6
    UriHostNameTypeDns
)

Step 2: Build the Validation Function

This function will check for IPv4/IPv6 first, then validate DNS domain rules (including IDN support via Punycode conversion):

func CheckHostName(host string) UriHostNameType {
    // Handle empty or whitespace-only hostnames
    if strings.TrimSpace(host) == "" {
        return UriHostNameTypeInvalid
    }

    // Check if it's a valid IPv4 or IPv6 address
    ip := net.ParseIP(host)
    if ip != nil {
        if ip.To4() != nil {
            return UriHostNameTypeIPv4
        }
        return UriHostNameTypeIPv6
    }

    // Convert internationalized domain names (IDNs) to ASCII Punycode
    asciiHost, err := idna.ToASCII(host)
    if err != nil {
        return UriHostNameTypeInvalid
    }

    // Validate DNS domain structure rules
    // Rule 1: No leading/trailing dots or consecutive dots
    if strings.HasPrefix(asciiHost, ".") || strings.HasSuffix(asciiHost, ".") || strings.Contains(asciiHost, "..") {
        return UriHostNameTypeInvalid
    }

    // Rule 2: Total domain length can't exceed 253 characters
    if len(asciiHost) > 253 {
        return UriHostNameTypeInvalid
    }

    // Rule 3: Validate each domain label (split by dots)
    labels := strings.Split(asciiHost, ".")
    for _, label := range labels {
        // Labels must be 1-63 characters long
        if len(label) == 0 || len(label) > 63 {
            return UriHostNameTypeInvalid
        }
        // Labels can't start or end with a hyphen
        if strings.HasPrefix(label, "-") || strings.HasSuffix(label, "-") {
            return UriHostNameTypeInvalid
        }
        // Labels can only contain alphanumeric characters or hyphens
        for _, c := range label {
            if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-') {
                return UriHostNameTypeInvalid
            }
        }
    }

    // All checks passed: it's a valid DNS domain
    return UriHostNameTypeDns
}

Validating a URL's Hostname() in Go

To validate the hostname extracted from a URL, use Go's net/url package to parse the URL, then pass the Hostname() result to our CheckHostName function. This automatically handles port numbers and IPv6 bracket stripping (matching .NET's URI.Host behavior):

import "net/url"

func ValidateURLHostname(urlStr string) UriHostNameType {
    parsedURL, err := url.Parse(urlStr)
    if err != nil {
        return UriHostNameTypeInvalid
    }
    // Hostname() removes ports and IPv6 brackets for us
    hostname := parsedURL.Hostname()
    return CheckHostName(hostname)
}

Test Cases to Verify Behavior

Here are some test cases to ensure our implementation matches .NET's behavior:

func main() {
    testCases := []struct {
        host     string
        expected UriHostNameType
    }{
        {"example.com", UriHostNameTypeDns},
        {"192.168.1.1", UriHostNameTypeIPv4},
        {"::1", UriHostNameTypeIPv6},
        {"例子.com", UriHostNameTypeDns}, // IDN (international domain)
        {"example..com", UriHostNameTypeInvalid},
        {"-example.com", UriHostNameTypeInvalid},
        {"example-.com", UriHostNameTypeInvalid},
        {"a" + strings.Repeat("a", 63) + ".com", UriHostNameTypeInvalid}, // Label too long
        {"[::1]", UriHostNameTypeInvalid}, // Bracketed IPv6 is invalid (use URL.Hostname() to fix)
        {"", UriHostNameTypeInvalid},
    }

    for _, tc := range testCases {
        result := CheckHostName(tc.host)
        status := "PASS"
        if result != tc.expected {
            status = "FAIL"
        }
        println(status, ":", tc.host, "→ expected", tc.expected, "got", result)
    }
}

内容的提问来源于stack exchange,提问作者user6216224

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:08:50