URL验证似乎破了

nin*_*alt -2 validation url go

我正在尝试使用Go的标准库验证URL.这是我的代码目前的样子.

import (
    "fmt"
    "net/url"
)

func isValidURL(tocheck string) bool {
    _, err := url.ParseRequestURI(tocheck)
    return err == nil
}

func main() {
    fmt.Println(isValidURL("google.com"))      //returns false, expected true
    fmt.Println(isValidURL("www.google.com"))  //returns false, expected true
    fmt.Println(isValidURL("google"))          //returns false, expected false
    fmt.Println(isValidURL("/google"))         //returns true, expected false
}
Run Code Online (Sandbox Code Playgroud)

尽管前两个应该是真的,但所有三个示例都打印为false.然后我尝试追加https://到不以它们开头的URL的开头,但随后一切都https://aaaa被解析为有效.我该怎么做才能确保它只在URL实际有效时才返回true?

Sch*_*ern 5

其中大多数是域名.https://aaaa是一个有效的URL./google不是URL,但可以接受,ParseRequestURI因为它也接受绝对路径.

" rawurl仅被解释为绝对URI 或绝对路径 "

当您ParseRequestURI要求对绝对URL或绝对路径进行严格的语法检查时.绝对的路径就是这样/foo/bar.RFC 3986涵盖了什么是非绝对URL .URI的基本语法是这样的.

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

hier-part   = "//" authority path-abempty
            / path-absolute
            / path-rootless
            / path-empty
Run Code Online (Sandbox Code Playgroud)

"绝对URL"表示该path部分是绝对路径或空,所以path-abemptypath-absolute更高.httphttpsURL只能是绝对的.foo:bar/baz是相对URL的示例.

这是一个例子.

  foo://example.com:8042/over/there?name=ferret#nose
  \_/   \______________/\_________/ \_________/ \__/
   |           |            |            |        |
scheme     authority       path        query   fragment
   |   _____________________|__
  / \ /                        \
  urn:example:animal:ferret:nose
Run Code Online (Sandbox Code Playgroud)

google.com没有scheme,所以它不是一个URL.https://aaaa有一个方案,https并且hier-part,//aaaa,所以它是一个URL.它没有queryfragement,但它们是可选的.

显然这有点宽泛.在现实世界中,您需要缩小您的要求.通常它就像......

  1. 验证它是一个URL,你不是通过调用做的,ParseRequestURI因为它也可以是一个绝对路径.
  2. 检查它是否有可接受的方案url.Scheme.这将丢弃绝对路径.
  3. 检查它是否具有有效的域名url.Host.

以及您可能想要做的任何其他检查,以限制您认为有效的URL.

所以你的全面检查可能看起来像......

package main

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

func isValidURL(tocheck string) (bool, error) {
    // Check it's an Absolute URL or absolute path
    uri, err := url.ParseRequestURI(tocheck)
    if err != nil {
        return false, err
    }

    // Check it's an acceptable scheme
    switch uri.Scheme {
        case "http":
        case "https":
        default:
            return false, errors.New("Invalid scheme")
    }

    // Check it's a valid domain name
    _,err = net.LookupHost(uri.Host)
    if err != nil {
        return false, err
    }

    return true, nil
}

func main() {
    // False, no scheme
    fmt.Println(isValidURL("/google"))
    // True, good scheme, good domain
    fmt.Println(isValidURL("https://google.com"))
    // False, bad domain
    fmt.Println(isValidURL("http://halghalghlakdjfl.blarg"))
}
Run Code Online (Sandbox Code Playgroud)