GO CURL

作者: JunChow520 | 来源:发表于2021-03-25 10:44 被阅读0次

    Golang内置net/http包中http.Client结构用于实现HTTP客户端,因此无需借助第三方网络通信库(如libcurl)就可以直接使用GET或POST方式发起HTTP请求,实现远程请求页面。

    type Client struct {
        Transport RoundTripper//HTTP请求创建机制,如果为空将会使用DefaultTransport。
        CheckRedirect func(req *Request, via []*Request) error//重定向策略
        Jar CookieJar //如果Jar为空,Cookie将不会在请求中发送,并会在响应中被忽略。
        Timeout time.Duration
    }
    
    属性 描述
    Transport HTTP事务用于处理客户端的请求并等待服务端的响应
    CheckRedirect 指定处理重定向的策略
    Jar 指定COOKIE的Jar
    Timeout 指定客户端请求的最大超时时间

    http.Client被设计成上下两层结构

    • 上层:业务层

    上层封装的基础方法可称之为业务层,因为调用方通常只需要关心请求的业务逻辑本身,而无需关心非业务相关的技术细节。

    • 下层:传输层

    由于http.Client在底层抽象了http.RoundTripper接口,而http.Transport实现了该接口,从而能够处理更多细节,可将其视为下层的“传输层”。

    Transport 指定执行HTTP请求的运行机制,可用于设置HTTP底层传输细节、HTTP代理、GZIP压缩、连接池及其管理、SSL认证等。

    http.Client

    发送JSON数据

    func HTTPJson(method string, url string, params []byte) ([]byte, error) {
        body := bytes.NewBuffer(params)
        req, err := http.NewRequest(method, url, body)
        if err != nil {
            return nil, err
        }
    
        req.Header.Set("Content-Type", "application/json")
    
        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
            return nil, err
        }
        if resp != nil {
            defer resp.Body.Close()
        }
        if resp.StatusCode == http.StatusOK {
            msg := fmt.Sprintf("response status code %v", resp.StatusCode)
            return nil, errors.New(msg)
        }
    
        bs, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }
    
        return bs, nil
    }
    

    client.Do

    func (c *Client) Do(req *Request) (*Response, error) {
        return c.do(req)
    }
    
    func HTTPDo(method string, url string, values url.Values) ([]byte, error) {
        body := strings.NewReader(values.Encode())
    
        req, err := http.NewRequest(method, url, body)
        if err != nil {
            return nil, err
        }
    
        //req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
        //req.Header.Set("Cookie", cookie)
        //req.Header.Set("Connection", "keep-alive")
        //req.Header.Add("x-requested-with", "XMLHttpRequest") //AJAX
    
        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
            return nil, err
        }
        if resp != nil {
            defer resp.Body.Close()
        }
        if resp.StatusCode == http.StatusOK {
            msg := fmt.Sprintf("response status code %v", resp.StatusCode)
            return nil, errors.New(msg)
        }
    
        bs, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }
        return bs, nil
    }
    

    http.NewRequest

    func NewRequest(method, url string, body io.Reader) (*Request, error) {
        return NewRequestWithContext(context.Background(), method, url, body)
    }
    

    http.Get

    func Get(url string) (resp *Response, err error) {
        return DefaultClient.Get(url)
    }
    func (c *Client) Get(url string) (resp *Response, err error) {
        req, err := NewRequest("GET", url, nil)
        if err != nil {
            return nil, err
        }
        return c.Do(req)
    }
    
    func HTTPGet(url string) ([]byte, error) {
        //发送请求获取响应
        resp, err := http.Get(url)
        if err != nil {
            return nil, err
        }
        //结束网络释放资源
        if resp != nil {
            defer resp.Body.Close()
        }
        //判断响应状态码
        if resp.StatusCode != http.StatusOK {
            return nil, errors.New(fmt.Sprintf("response status code %v", resp.StatusCode))
        }
    
        //读取响应实体
        bs, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }
        return bs, nil
    }
    

    通过http.Get发起请求时,默认调用的是http.Client默认对象上的Get方法。

    func Get(url string) (resp *Response, err error) {
        return DefaultClient.Get(url)
    }
    

    DefaultClient默认指向的正是http.Client的实例对象。

    var DefaultClient = &Client{}
    

    http.Get()方法返回值

    func (c *Client) Get(url string) (resp *Response, err error) {
        req, err := NewRequest("GET", url, nil)
        if err != nil {
            return nil, err
        }
        return c.Do(req)
    }
    
    返回值 类型 描述
    resp *http.Response 响应对象
    err error 错误对象

    若请求过程中出现错误则error对象不为空,否则可通过resp响应对象获取响应码、响应头、响应实体等信息。

    响应 描述
    resp.StatusCode 获取响应状态码
    resp.Header 获取响应头
    resp.Body 获取响应实体

    http.Post

    func Post(url, contentType string, body io.Reader) (resp *Response, err error) {
        return DefaultClient.Post(url, contentType, body)
    }
    
    • HTTP POST请求的参数需要通过url.Values进行编码和封装
    func HTTPPost(url string, params url.Values, contentType string) ([]byte, error) {
    
        body := strings.NewReader(params.Encode())
    
        if contentType == "" {
            contentType = "application/x-www-form-urlencoded"
        }
    
        resp, err := http.Post(url, contentType, body)
        if err != nil {
            return nil, err
        }
        if resp != nil {
            defer resp.Body.Close()
        }
        if resp.StatusCode != http.StatusOK {
            return nil, errors.New(fmt.Sprintf("response status code %v", resp.StatusCode))
        }
    
        bs, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }
    
        return bs, nil
    }
    

    http.PostForm

    func PostForm(url string, data url.Values) (resp *Response, err error) {
        return DefaultClient.PostForm(url, data)
    }
    func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
        return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
    }
    
    func HTTPPostForm(url string, values url.Values) ([]byte, error) {
        resp, err := http.PostForm(url, values)
        if err != nil {
            return nil, err
        }
        if resp != nil {
            defer resp.Body.Close()
        }
        if resp.StatusCode != http.StatusOK {
            return nil, errors.New(fmt.Sprintf("response status code %v", resp.StatusCode))
        }
    
        bs, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }
    
        return bs, nil
    }
    

    url.Values

    转化参数为 id=1&name=admin&pid=0 格式

    func MakeParams(params url.Values) string {
        var keys []string
        for k := range params {
            keys = append(keys, k)
        }
        sort.Strings(keys)
    
        bb := bytes.Buffer{}
        for _, key := range keys {
            val := params.Get(key)
            bb.WriteString(key)
            bb.WriteString("=")
            bb.WriteString(val)
            bb.WriteString("&")
        }
    
        return strings.TrimRight(bb.String(), "&")
    }
    
    $ vim ./test/ins_test.go
    
    package test
    
    import (
        "gfw/web"
        "net/url"
        "testing"
    )
    
    func TestCurl(t *testing.T) {
        params := url.Values{}
        params.Add("id", "1")
        params.Add("name", "admin")
        params.Add("pid", "0")
    
        body := web.MakeParams(params)
        t.Log(body)
    }
    
    $ go test -v -run TestCurl ins_test.go
    === RUN   TestCurl
        ins_test.go:16: id=1&name=admin&pid=0
    --- PASS: TestCurl (0.00s)
    PASS
    ok      command-line-arguments  0.300s
    

    相关文章

      网友评论

          本文标题:GO CURL

          本文链接:https://www.haomeiwen.com/subject/vynchltx.html