亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Golang實(shí)現(xiàn)驗(yàn)證一個(gè)字符串是否為URL

 更新時(shí)間:2023年04月18日 10:22:25   作者:宇宙之一粟  
在實(shí)際開(kāi)發(fā)過(guò)程中,有時(shí)候會(huì)遇到?URL?的校驗(yàn)問(wèn)題,Go?語(yǔ)言中有哪些方法去驗(yàn)證一個(gè)字符串是否滿足?URL?格式呢?本文就來(lái)和大家詳細(xì)講講

前言

在實(shí)際開(kāi)發(fā)過(guò)程中,有時(shí)候會(huì)遇到 URL 的校驗(yàn)問(wèn)題,其實(shí)我也是直接調(diào)用了第三方庫(kù),但是也引發(fā)了一個(gè)思考,Go 語(yǔ)言中有哪些方法去驗(yàn)證一個(gè)字符串是否滿足 URL 格式呢?

URL 代表唯一資源定位符,是 URI 的子類型(盡管許多人可以互換使用這兩個(gè)術(shù)語(yǔ))。URL 是對(duì)網(wǎng)絡(luò)資源的引用,通常被視為網(wǎng)址(例如 https://golang.org)。

下面你可以看到一個(gè) URL 的結(jié)構(gòu),它符合 URI 的結(jié)構(gòu)

URI = scheme:[//authority]path[?query][#fragment]
authority = [userinfo@]host[:port]

官方 URL 包

在 Golang 中利用 url.ParseRequestURI 可以簡(jiǎn)單驗(yàn)證我們的 URL。

func ParseRequestURI(rawurl string) (*URL, error)

ParseRequestURI 將 rawurl 解析成 URL 結(jié)構(gòu)。它假定在HTTP請(qǐng)求中接收到 rawurl,因此 rawurl 僅被解釋為絕對(duì) URI 或絕對(duì)路徑。假定字符串 rawurl 沒(méi)有 #fragment 后綴。(Web 瀏覽器在將 URL 發(fā)送到 Web 服務(wù)器之前去除 #fragment。)

ParseRequestURI 與 Parse

還有另一種方法應(yīng)該用于解析 URL 字符串,但有一些注意事項(xiàng)。它允許相對(duì) URL 使驗(yàn)證更加寬松。它是url.Parse

func Parse(rawurl string) (*URL, error)

如文檔中所述:

Parse 將 rawurl 解析成 URL 結(jié)構(gòu)。
rawurl 可以是相對(duì)的(路徑,沒(méi)有主機(jī))或絕對(duì)的(以方案開(kāi)頭)。嘗試在沒(méi)有方案的情況下解析主機(jī)名和路徑是無(wú)效的,但由于解析歧義,不一定會(huì)返回錯(cuò)誤。

比如如下的例子:

package main

import (
	"fmt"
	"net/url"
)

func main() {

	str := "http://yuzhou1u.com"

	var validURL bool

	_, err := url.Parse(str)

	if err != nil {
		fmt.Println(err)
		validURL = false
	} else {
		validURL = true
	}

	fmt.Printf("%s is a valid URL : %v \n", str, validURL)

}

使用 ParseRequestURI

在 Google 解決方法的時(shí)候,根據(jù)這篇教程中 How to check if a string is a valid URL in Golang? 提供的方法,寫(xiě)了一個(gè)函數(shù):

func isValidUrl(u1 string) bool {

	_, err := url.ParseRequestURI(u1)
	if err != nil {
		return false
	}

	u, err := url.Parse(u1)
	if err != nil || u.Scheme == "" || u.Host == "" {
		return false
	}

	// Check if the URL has a valid scheme (http or https)
	if u.Scheme != "http" && u.Scheme != "https" {
		return false
	}

	return true
}

使用這個(gè)方法也有個(gè)缺陷,如果是多個(gè) schema:https,也是檢查不出來(lái)的,例如下面的示例:

package main

import (
	"fmt"
	"net/url"
)

func main() {

	fmt.Println(isValidUrl("testURL"))

	fmt.Println(isValidUrl("test.test/"))

	fmt.Println(isValidUrl("http://goglang.org"))

	fmt.Println(isValidUrl("https://goglang.org"))

	fmt.Println(isValidUrl("https://https://https://../google.com"))
}

func isValidUrl(u1 string) bool {

	_, err := url.ParseRequestURI(u1)
	if err != nil {
		return false
	}

	u, err := url.Parse(u1)
	if err != nil || u.Scheme == "" || u.Host == "" {
		return false
	}

	// Check if the URL has a valid scheme (http or https)
	if u.Scheme != "http" && u.Scheme != "https" {
		return false
	}

	return true
}

運(yùn)行結(jié)果如圖:

使用 url-verifier 包

安裝:go get -u github.com/davidmytton/url-verifier

package main

import (
	"fmt"

	urlverifier "github.com/davidmytton/url-verifier"
)

func main() {

	url := "https://https://https://../google.com"

	verifier := urlverifier.NewVerifier()

	ret, err := verifier.Verify(url)

	if err != nil {
		fmt.Errorf("Error: %s", err)
	}

	fmt.Printf("Result: %+v\n", ret)

}

運(yùn)行結(jié)果:

后面在研究這部分 verifier.go 源碼時(shí),發(fā)現(xiàn)這個(gè)用了 govalidator 這個(gè)包,如圖:

于是,我們何不直接使用 govalidator 包來(lái)判斷一個(gè)字符串是否是 URL 呢?

使用 govalidator 包

govalidator 是一個(gè)針對(duì)字符串、結(jié)構(gòu)體和集合的驗(yàn)證器和包?;?validator.js。

GitHub 地址:github.com/asaskevich/govalidator , 目前收獲了 5.7k 的 star

安裝:go get github.com/asaskevich/govalidator

package main

import (
	"fmt"

	"github.com/asaskevich/govalidator"
)

func main() {

	str := "https://https://https://../google.com"

	validURL := govalidator.IsURL(str)

	fmt.Printf("%s is a valid URL : %v \n", str, validURL)
}

運(yùn)行結(jié)果如下:

正則表達(dá)式匹配

本來(lái)想自己寫(xiě)正則表達(dá)式匹配的,然后發(fā)現(xiàn) govalidator 包的作者背后的原理也是用了正則表達(dá)式的,

然后就偷懶了,直接把他源碼中的部分集合到一個(gè) main.go 函數(shù)中:

package main

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"
	"unicode/utf8"
)

const (
	URLSchema    string = `((ftp|tcp|udp|wss?|https?):\/\/)`
	URLUsername  string = `(\S+(:\S*)?@)`
	URLPath      string = `((\/|\?|#)[^\s]*)`
	URLPort      string = `(:(\d{1,5}))`
	URLIP        string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))`
	IP           string = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
	URLSubdomain string = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
	URL                 = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`

	/*MaxURLRuneCount : maxima cantidad de runas por contar*/
	MaxURLRuneCount = 2083
	/*MinURLRuneCount : minima cantidad de runas por contar*/
	MinURLRuneCount = 3
)

var rxURL = regexp.MustCompile(URL)

// IsURL checks if the string is an URL.
func IsURL(str string) bool {
	if str == "" || utf8.RuneCountInString(str) >= MaxURLRuneCount || len(str) <= MinURLRuneCount || strings.HasPrefix(str, ".") {
		return false
	}
	strTemp := str
	if strings.Contains(str, ":") && !strings.Contains(str, "://") {
		// support no indicated urlscheme but with colon for port number
		// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
		strTemp = "http://" + str
	}
	u, err := url.Parse(strTemp)
	if err != nil {
		return false
	}
	if strings.HasPrefix(u.Host, ".") {
		return false
	}
	if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
		return false
	}
	return rxURL.MatchString(str)
}

func main() {

	fmt.Println(IsURL("testURL"))

	fmt.Println(IsURL("test.test/"))

	fmt.Println(IsURL("http://goglang.org"))

	fmt.Println(IsURL("https://goglang.org"))

	fmt.Println(IsURL("https://https://https://../google.com"))
}

運(yùn)行結(jié)果:

除了校驗(yàn) URL,這個(gè)包還提供了眾多的字符串校驗(yàn)方法,例如校驗(yàn)郵箱、信用卡格式、IP...

總結(jié)

數(shù)據(jù)校驗(yàn)是每個(gè)程序員日常開(kāi)發(fā)過(guò)程的一部分,尤其是在從事后端服務(wù)時(shí),數(shù)據(jù)驗(yàn)證必須嚴(yán)格,保持正確。

在這篇文章中,我們討論了如何在 Go 語(yǔ)言中正確驗(yàn)證一個(gè)字符串是否是 URL,當(dāng)然利用了官方包和優(yōu)秀的第三方包,在實(shí)際過(guò)程中,可能我們?yōu)榱撕?jiǎn)便會(huì)直接使用別人開(kāi)發(fā)好的工具,但是在學(xué)習(xí)過(guò)程中,不妨也去思考別人實(shí)現(xiàn)的原理,結(jié)合實(shí)際業(yè)務(wù)需要,進(jìn)而擴(kuò)展成自己的工具包。

以上就是Golang實(shí)現(xiàn)驗(yàn)證一個(gè)字符串是否為URL的詳細(xì)內(nèi)容,更多關(guān)于Golang驗(yàn)證字符串是否為URL的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go標(biāo)準(zhǔn)庫(kù)http與fasthttp服務(wù)端性能對(duì)比場(chǎng)景分析

    Go標(biāo)準(zhǔn)庫(kù)http與fasthttp服務(wù)端性能對(duì)比場(chǎng)景分析

    這篇文章主要介紹了Go標(biāo)準(zhǔn)庫(kù)http與fasthttp服務(wù)端性能比較,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • Go并發(fā)編程之死鎖與活鎖的案例分析

    Go并發(fā)編程之死鎖與活鎖的案例分析

    死鎖就是在并發(fā)程序中,兩個(gè)或多個(gè)線程彼此等待對(duì)方完成操作,從而導(dǎo)致它們都被阻塞,并無(wú)限期地等待對(duì)方完成;活鎖就是程序一直在運(yùn)行,但是無(wú)法取得進(jìn)展。本文將從一些案例出發(fā),分析一下它們,希望對(duì)大家有所幫助
    2023-04-04
  • go 生成器模式的具體使用

    go 生成器模式的具體使用

    生成器是一種創(chuàng)建型設(shè)計(jì)模式,使你能夠分步驟創(chuàng)建復(fù)雜對(duì)象,本文主要介紹了go生成器模式的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 在Go網(wǎng)絡(luò)請(qǐng)求中配置代理的方法詳解

    在Go網(wǎng)絡(luò)請(qǐng)求中配置代理的方法詳解

    這篇文章主要給大家介紹了如何在Go網(wǎng)絡(luò)請(qǐng)求中配置代理的方法,文章通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-09-09
  • go mayfly開(kāi)源項(xiàng)目代碼結(jié)構(gòu)設(shè)計(jì)

    go mayfly開(kāi)源項(xiàng)目代碼結(jié)構(gòu)設(shè)計(jì)

    這篇文章主要為大家介紹了go mayfly開(kāi)源項(xiàng)目代碼結(jié)構(gòu)設(shè)計(jì)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Go語(yǔ)言學(xué)習(xí)教程之聲明語(yǔ)法(譯)

    Go語(yǔ)言學(xué)習(xí)教程之聲明語(yǔ)法(譯)

    Golang 就是類C的語(yǔ)法,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言學(xué)習(xí)教程之聲明語(yǔ)法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • Go如何優(yōu)雅的關(guān)閉goroutine協(xié)程

    Go如何優(yōu)雅的關(guān)閉goroutine協(xié)程

    本文將介紹首先為什么需要主動(dòng)關(guān)閉goroutine,并介紹如何在Go語(yǔ)言中關(guān)閉goroutine的常見(jiàn)套路,包括傳遞終止信號(hào)和協(xié)程內(nèi)部捕捉終止信號(hào),之后,文章列舉了需要主動(dòng)關(guān)閉協(xié)程運(yùn)行的常見(jiàn)場(chǎng)景,希望通過(guò)本文的介紹,讀者能夠掌握如何在適當(dāng)?shù)臅r(shí)候關(guān)閉goroutine
    2023-05-05
  • Go基于GORM 獲取當(dāng)前請(qǐng)求所執(zhí)行的 SQL 信息(思路詳解)

    Go基于GORM 獲取當(dāng)前請(qǐng)求所執(zhí)行的 SQL 信息(思路詳解)

    這篇文章主要介紹了Go基于GORM 獲取當(dāng)前請(qǐng)求所執(zhí)行的 SQL 信息(思路詳解),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • golang中結(jié)構(gòu)體嵌套接口的實(shí)現(xiàn)

    golang中結(jié)構(gòu)體嵌套接口的實(shí)現(xiàn)

    本文主要介紹了golang中結(jié)構(gòu)體嵌套接口的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • golang新手們?nèi)菀追傅?個(gè)錯(cuò)誤總結(jié)

    golang新手們?nèi)菀追傅?個(gè)錯(cuò)誤總結(jié)

    這篇文章主要給大家介紹了關(guān)于golang新手們?nèi)菀追傅?個(gè)錯(cuò)誤,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08

最新評(píng)論