确保URI有效

I'm trying to ensure that URLs passed to my go program are valid. However, I can't seem to work out how to. I thought I could just feed it through url.Parse, but that doesn't seem to do the job.

package main

import (
    "fmt"
    "net/url"
)

func main() {
    url, err := url.Parse("http:::/not.valid/a//a??a?b=&&c#hi")
    if err != nil {
        panic(err)
    }
    fmt.Println("It's valid!", url.String())
}

playground

Is there anything along the lines of filter_var I can use?

You can check that your URL has a Scheme, Host, and/or a Path.

If you inspect the URL returned, you can see that the invalid part is inserted into the Opaque data section (so in a sense, it is valid).

url.URL{Scheme:"http", Opaque:"::/not.valid/a//a", Host:"", Path:"", RawQuery:"?a?b=&&c", Fragment:"hi"}

If you parse a URL and don't have a Scheme, Host and Path you can probably assume it's not valid. (though a host without a path is often OK, since it implies /, so you need to check for that)

u, err := url.Parse("http:::/not.valid/a//a??a?b=&&c#hi")
if err != nil {
    log.Fatal(err)
}

if u.Scheme == "" || u.Host == "" || u.Path == "" {
    log.Fatal("invalid URL")
}

The url.Parse() function will return an error mainly if viaRequest is true, meaning if the URL is assumed to have arrived via an HTTP request.
Which is not the case when you call url.Parse() directly: see the source code.

if url, err = parse(u, false); err != nil {
    return nil, err
}

And func parse(rawurl string, viaRequest bool) (url *URL, err error) { only returns err if viaRequest is true.

That is why you never see any error when using url.Parse() directly.


In that latter case, where no err is ever returned, you can check the fields of the URL object returned.
An empty url.Scheme, or an url.Path which isn't the one expected would indicate an error.

have a try of this package go validator and the IsURL func is what you want.(you can use regexp package as well)

package main

import (
    "fmt"
    "regexp"
)

const URL string = `^((ftp|http|https):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(((([a-z\x{00a1}-\x{ffff}0-9]+-?-?_?)*[a-z\x{00a1}-\x{ffff}0-9]+)\.)?)?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?_?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?)|localhost)(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`

func Matches(str, pattern string) bool {
    match, _ := regexp.MatchString(pattern, str)
    return match
}
func main() {
    u1 := "http:::/not.valid/a//a??a?b=&&c#hi"
    u2 := "http://golang.fastrl.com"
    func(us ...string) {
        for _, u := range us {
            fmt.Println(Matches(u, URL))
        }
    }(u1, u2)
}