urlx.go
func SplitHostPort(u *url.URL) (host, port string, err error) {
	if u == nil {
		return "", "", &url.Error{Op: "host", URL: host, Err: errors.New("empty url")}
	}
	host = u.Host

	// Find last colon.
	if i := strings.LastIndex(host, ":"); i != -1 {
		// If we're not inside [IPv6] brackets, split host:port.
		if len(host) > i && !strings.Contains(host[i:], "]") {
			port = host[i+1:]
			host = host[:i]
		}
	}

	// Port is optional. But if it's set, is it a number?
	if port != "" {
		if _, err := strconv.Atoi(port); err != nil {
			return "", "", &url.Error{Op: "port", URL: host, Err: err}
		}
	}

	return host, port, nil
}
func SplitHostPort(u *url.URL) (host, port string, err error) {
	if u == nil {
		return "", "", &url.Error{Op: "host", URL: host, Err: errors.New("empty url")}
	}
	host = u.Host

	// Find last colon.
	if i := strings.LastIndex(host, ":"); i != -1 {
		// If we're not inside [IPv6] brackets, split host:port.
		if len(host) > i && !strings.Contains(host[i:], "]") {
			port = host[i+1:]
			host = host[:i]
		}
	}

	// Port is optional. But if it's set, is it a number?
	if port != "" {
		if _, err := strconv.Atoi(port); err != nil {
			return "", "", &url.Error{Op: "port", URL: host, Err: err}
		}
	}

	return host, port, nil
}
// SplitHostPort splits network address of the form "host:port" into
// host and port. Unlike net.SplitHostPort(), it doesn't remove brackets
// from [IPv6] host and it accepts net/url.URL struct instead of a string.