A Bite of GoLang (8)

叁叁肆2018-09-19 11:29

本文来自网易云社区


作者:盛国存


10. Http及其他标准库

10.0、Http标准库介绍

Go语言有很多的标准库,http库是最重要的之一,它对Http的封装也是非常完善的,之前我们有演示过服务端的一些基础使用,下面我们介绍一些客户端相关的使用

1、使用http客户端发送请求

package main

import (
    "net/http"
    "net/http/httputil"
    "fmt"
)

func main() {

    response, err := http.Get("https://www.shengguocun.com")
    if err != nil{
        panic(err)
    }
    defer response.Body.Close()

    ss, err := httputil.DumpResponse(response, true)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s \n", ss)
}

这里就把完整的头信息以及html的部分打印出来了。比如在我们现实的情境中,我们会根据UA做一些反作弊的策略,以及是否需要重定向到 M 端等等。这里的 http.Client 就能实现。

2、使用http.Client控制请求头

请求头信息直接通过 request.Header.Add 添加就可以了

package main

import (
    "net/http"
    "net/http/httputil"
    "fmt"
)

func main() {

    request, err := http.NewRequest(http.MethodGet,"https://www.shengguocun.com", nil)
    request.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36")
    response, err := http.DefaultClient.Do(request)
    if err != nil{
        panic(err)
    }
    defer response.Body.Close()

    ss, err := httputil.DumpResponse(response, true)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s \n", ss)
}

上面我们都用的是 DefaultClient ,我们也可以自己创建 client, 首先我们先看一下 Client 内部都有些什么

查看源码我们发现有一个 CheckRedirect ,我们发现这是一个检查重定向的函数。那我们就用它做一下演示

package main

import (
    "net/http"
    "net/http/httputil"
    "fmt"
)

func main() {

    request, err := http.NewRequest(http.MethodGet,"https://jim-sheng.github.io", nil)
    request.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36")
    client := http.Client{
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            fmt.Println("重定向地址:", req)
            return  nil
        },
    }
    response, err := client.Do(request)
    if err != nil{
        panic(err)
    }
    defer response.Body.Close()

    ss, err := httputil.DumpResponse(response, true)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s \n", ss)
}

输出结果(部分)

重定向地址: &{GET https://www.shengguocun.com/  0 0 map[User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36] Referer:[https://jim-sheng.github.io]] <nil> <nil> 0 [] false  map[] map[] <nil> map[]   <nil> <nil> 0xc42012c090 <nil>}
HTTP/2.0 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Origin: *

我们可以看到具体的重定向的地址 https://www.shengguocun.com/ ,其它的

// Transport specifies the mechanism by which individual
// HTTP requests are made.
// If nil, DefaultTransport is used.
Transport RoundTripper

主要用于代理

// Jar specifies the cookie jar.
//
// The Jar is used to insert relevant cookies into every
// outbound Request and is updated with the cookie values
// of every inbound Response. The Jar is consulted for every
// redirect that the Client follows.
//
// If Jar is nil, cookies are only sent if they are explicitly
// set on the Request.
Jar CookieJar

主要用于模拟登录用的

// Timeout specifies a time limit for requests made by this
// Client. The timeout includes connection time, any
// redirects, and reading the response body. The timer remains
// running after Get, Head, Post, or Do return and will
// interrupt reading of the Response.Body.
//
// A Timeout of zero means no timeout.
//
// The Client cancels requests to the underlying Transport
// using the Request.Cancel mechanism. Requests passed
// to Client.Do may still set Request.Cancel; both will
// cancel the request.
//
// For compatibility, the Client will also use the deprecated
// CancelRequest method on Transport if found. New
// RoundTripper implementations should use Request.Cancel
// instead of implementing CancelRequest.
Timeout time.Duration

主要设置超时的

3、http服务器性能分析

还是使用之前的代码

package main

import (
    "net/http"
    "os"
    "io/ioutil"

    _ "net/http/pprof"
)

type appHandler func(writer http.ResponseWriter, request *http.Request) error

func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {

    return func(writer http.ResponseWriter, request *http.Request) {


        err := handler(writer, request)
        if err != nil {
            switch {

                case os.IsNotExist(err):
                    http.Error(writer, http.StatusText(http.StatusNotFound), http.StatusNotFound)
            }
        }
    }
}

func main() {

    http.HandleFunc("/list/",
        errWrapper(func(writer http.ResponseWriter, request *http.Request) error {
            path := request.URL.Path[len("/list/"):]
            file, err := os.Open(path)
            if err != nil {
                return err
            }
            defer  file.Close()

            all, err := ioutil.ReadAll(file)
            if err != nil {
                return err
            }

            writer.Write(all)
            return nil
        }))

    err := http.ListenAndServe(":2872", nil)
    if err != nil {
        panic(err)
    }
}

还是一样的代码,只不过import多了一个 import _ "net/http/pprof" , 为什么会多一个下划线呢?因为代码没有使用到,会报错,加一个下划线就可以了。重启代码,我们就可以访问 http://localhost:2872/debug/pprof/

里面的 stacktrace 都可以查看到

我们可以查看 pprof 的源码,继续查看它的其他的使用方式

// Or to look at a 30-second CPU profile:
//
//    go tool pprof http://localhost:6060/debug/pprof/profile

比如这一段,我们可以查看30秒的CPU的使用情况。可以终端敲下该命令(替换成自己的监听的端口),获取出结果后敲下 web 命令就可以看下具体的代码哪些地方需要优化。其他的使用使用方式就不一一罗列了,有兴趣可以继续查阅。


10.1、其他库

其它的标准库就不过多罗列了, https://studygolang.com/pkgdoc 上面的中文版的文档已经非常详细了 。


11. 总结

Go语言给我们展现了不一样的世界观,没有类、继承、多态、重载,没有构造函数,没有断言,没有try/catch等等;上面是在学习Go语言的过程中,记录下来的笔记;也可能有部分地方存在偏颇,还望指点~~~


相关阅读:A Bite of GoLang (1)

A Bite of GoLang (2)

A Bite of GoLang (3)

A Bite of GoLang (4)

A Bite of GoLang (5)

A Bite of GoLang (6)

A Bite of GoLang (7)

A Bite of GoLang (8)


网易云免费体验馆0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区