GO的URL合法性檢查

原文連接:https://www.zhoubotong.site/post/67.html
Go 標準庫的net/url包提供的兩個函可以直接檢查URL合法性,不需要手動去正則匹配校驗。

下面可以直接使用ParseRequestURI()函數解析URL,當然這個只會驗證url格式,至於域名是否存在或註冊,不會檢查的,舉個例子:
package main

import (
    "fmt"
    "net/url"
)

func main() {
    url, err := url.ParseRequestURI("https://www.zhoubotong.site") // 注意這裏必須帶有http/https協議,
    //否則會被認定非合法url,但是使用//www.zhoubotong.sit,被返回空,所以error哪裏會被繞過,該示例代碼不夠嚴謹
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(url.Hostname())
}
輸出:[www.zhoubotong.site](http://www.zhoubotong.site),下面整個錯誤的url:
func main() {
    url, err := url.ParseRequestURI("www.zhoubotong.site") // www.zhoubotong.site" 或者zhoubotong.site"
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(url.Hostname())
}
輸出:parse "www.zhoubotong.site": invalid URI for request,既然上面的代碼不夠嚴謹,如何改善呢?完整代碼如下:
package main

import (
    "fmt"
    "net/url"
)

func main() {
    var u string = "https://www.zhoubotong.site"
    _, err := url.ParseRequestURI(u)
    if err != nil {
        fmt.Println(err)
        return
    }
    url, err := url.Parse(u)
    if err != nil || url.Scheme == "" || url.Host == "" {
        fmt.Println(err)
        return
    }
    fmt.Println(url.Hostname(), "success")
}
通過上面的兩個函數解析url鏈接,順便嘮叨介紹下這塊http/post請求的示例,Get請求示例:
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "time"
)

// 定義返回的響應體
type Response struct {
    Params  string            `json:"params"`
    Headers map[string]string `json:"headers"`
    Origin  string            `json:"origin"`
    Url     string            `json:"url"`
}

var remoteUrl string = "https://www.baidu.com"

// 獲取帶參數的http get請求響應數據
func getUrlParse() {
    data := url.Values{}
    data.Set("username", "喬峯")
    data.Set("sex", "male")
    u, err := url.ParseRequestURI(remoteUrl)
    if err != nil {
        fmt.Println(err)
    }
    u.RawQuery = data.Encode()
    fmt.Println(u.RawQuery)
    resp, err := http.Get(u.String())
    if err != nil {
        fmt.Println(err)
    }
    defer resp.Body.Close() // 一定要關閉釋放tcp連接
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(body))
}

// 解析get請求的返回的json結果到struct
func getResultToStruct() {
    resp, err := http.Get(remoteUrl)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    var res Response // 定義res爲Responser結構體
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    _ = json.Unmarshal(body, &res) // 注意這裏是&res 地址引用
    fmt.Printf("%#v\n", res)
}

//get 請求添加頭消息
func getHttpByHeader() {
    param := url.Values{}
    param.Set("username", "babala")
    param.Set("sex", "female")
    u, _ := url.ParseRequestURI(remoteUrl)
    u.RawQuery = param.Encode() // 把參數轉換成 sex=female&username=babala
    fmt.Println(u)
    //重點注意:如果我們直接使用默認的http,那麼它是沒有超時時間的。這樣就會帶來性能問題,具體稍後寫一篇詳細介紹這塊
    client := &http.Client{Timeout: 10 * time.Second}
    req, err := http.NewRequest("GET", u.String(), nil)
    if err != nil {
        fmt.Println(err)
    }
    // 添加請求頭header 參數
    req.Header.Add("username2", "風清揚")
    req.Header.Add("age1", "89")
    resp, _ := client.Do(req)
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(body))

}

func main() {
    getResultToStruct()
    getHttpByHeader()
}
發送post請求示例:
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "strings"
    "time"
)

var remoteUrl = "https://www.zhoubotong.site"

// 發送表單post請求
func postByForm() {
    param := url.Values{}
    param.Add("username", "喬峯")
    param.Add("sex", "male")
    resp, _ := http.PostForm(remoteUrl, param) // 表單提交"Content-Type": "application/x-www-form-urlencoded"
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

// 發送表單提交,可以對比上面的postByForm的實現差異
func postByForm2() {
    urlValue := url.Values{
    "username": {"喬峯"},
    "sex":      {"male"},
}
    respData := urlValue.Encode()
    fmt.Println(respData) // encode轉碼:name=%E4%B9%94%E5%B3%B0&sex=male
    resp, _ := http.Post(remoteUrl, "text/html", strings.NewReader(respData))
    //注意接收數據類型爲text/html,對應在postman中的x-www-form-urlencoded中的key value參數
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

// 發送json數據
func postJson() {
    client := &http.Client{Timeout: time.Second * 10}
    param := make(map[string]interface{})
    param["username"] = "喬峯"
    param["sex"] = "male"
    respdata, _ := json.Marshal(param) // respdata[]byte類型,轉化成string類型便於查看
    req, _ := http.NewRequest("POST", remoteUrl, bytes.NewReader(respdata))
    //http.NewRequest請求會自動發送header中的Content-Type爲applcation/json,對應在postman中的body的raw的json參數
    resp, _ := client.Do(req)
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

// 發送json數據,注意和上面實現的區別
func postJson2() {
    param := make(map[string]interface{})
    param["username"] = "喬峯"
    param["sex"] = "male"
    respdata, _ := json.Marshal(param) // respdata[]byte類型,轉化成string類型便於查看
    fmt.Println(string(respdata))
    resp, _ := http.Post(remoteUrl, "application/json", bytes.NewReader(respdata))
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

/*
對應的postman中params中的key value參數,我估計很多人都很迷惑postman工具的params和body兩個地方傳遞參數的區別,
其實Params處設置的變量請求時會url後問號傳參(?x=y)。而Body裏設置的參數則是接口真正請求時發的參數,下面這個例子就是通過params傳參
*/
func postString() {
    param := url.Values{}
    param.Add("username", "babala")
    param.Add("sex", "female")
    u, _ := url.ParseRequestURI(remoteUrl)
    u.RawQuery = param.Encode()
    fmt.Println(u)
    client := &http.Client{}
    req, _ := http.NewRequest("POST", u.String(), nil) // 注意發送數據類似爲string的post請求,對應的postman中params中的key value參數
    resp, _ := client.Do(req)
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

func main() {
    //postByForm()
    //postByForm2()
    //postJson()
    //postJson2()
    postString()

}
通過上面的示例介紹,涉及了日常開發中各種場景的請求類型,基本滿足了常規開發,以上只是示例,後端如何處理數據,大家可以自行解析參數返回試試。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章