Golang下的net/http模块学习使用

2018-04-27  本文已影响581人  9c46ece5b7bd

包名:net/http

功能预览

http包主要提供了http客户端和服务端的实现。

Get,Head,Post,PostForm请求:

resp, err := http.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
...
resp, err := http.PostForm("http://example.com/form",
    url.Values{"key": {"Value"}, "id": {"123"}})

当获取到响应体的时候,客户端必须手动关闭链接:

resp, err := http.Get("http://example.com/")
if err != nil {
    // handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
// ...

控制Http客户端headers,redirect策略以及其他的设置,需要这样创建一个Client:

client := &http.Client{
    CheckRedirect: redirectPolicyFunc,
}

resp, err := client.Get("http://example.com")
// ...

req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
// ...

控制代理,TLS配置,keep-alives,压缩以及其他的设置,需要创建一个Transport:

tr := &http.Transport{
    MaxIdleConns:       10,
    IdleConnTimeout:    30 * time.Second,
    DisableCompression: true,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://example.com")

ClientsTransports在多个goroutines在并发使用的时候是比较安全的,而且为了效率,应该创建一次重复使用。

ListenAndServe根据指定的地址和handler来启动一个http server.一般来说,这个handler通常会设置为nil,这意味着使用默认的DefaultServeMux.HandleHandleFunc用来增加handler到DefaultServeMux:

http.Handle("/foo", fooHandler)

http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})

log.Fatal(http.ListenAndServe(":8080", nil))

更多用来控制服务端行为可以创建一个自定义的Server:

s := &http.Server{
    Addr:           ":8080",
    Handler:        myHandler,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())

默认从Golang1.6开始,当使用https时http包默认提供HTTP/2 的传输支持。程序必须通过设置Transport.TLSNextProto 或者Server.TLSNextProto为非空值或者空的map,才能关闭HTTP/2. 以下可选的环境变量在当前也是支持的:

GODEBUG=http2client=0  # disable HTTP/2 client support
GODEBUG=http2server=0  # disable HTTP/2 server support
GODEBUG=http2debug=1   # enable verbose HTTP/2 debug logs
GODEBUG=http2debug=2   # ... even more verbose, with frame dumps

需要注意的是,http包的TransportServer都自动开启了HTTP/2,当然只是一些简单的配置,更复杂的配置需要使用http2包来配置,官方默认包中已经提供了http2包,也可以通过导入golang.org/x/net/http2来进行更复杂配置的支持。

常用函数方法以及变量

常量:

const (
        MethodGet     = "GET"
        MethodHead    = "HEAD"
        MethodPost    = "POST"
        MethodPut     = "PUT"
        MethodPatch   = "PATCH" // RFC 5789
        MethodDelete  = "DELETE"
        MethodConnect = "CONNECT"
        MethodOptions = "OPTIONS"
        MethodTrace   = "TRACE"
)

const (
        StatusContinue           = 100 // RFC 7231, 6.2.1
        StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
        StatusProcessing         = 102 // RFC 2518, 10.1

        StatusOK                   = 200 // RFC 7231, 6.3.1
        StatusCreated              = 201 // RFC 7231, 6.3.2
        StatusAccepted             = 202 // RFC 7231, 6.3.3
        StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
        StatusNoContent            = 204 // RFC 7231, 6.3.5
        StatusResetContent         = 205 // RFC 7231, 6.3.6
        StatusPartialContent       = 206 // RFC 7233, 4.1
        StatusMultiStatus          = 207 // RFC 4918, 11.1
        StatusAlreadyReported      = 208 // RFC 5842, 7.1
        StatusIMUsed               = 226 // RFC 3229, 10.4.1

        StatusMultipleChoices  = 300 // RFC 7231, 6.4.1
        StatusMovedPermanently = 301 // RFC 7231, 6.4.2
        StatusFound            = 302 // RFC 7231, 6.4.3
        StatusSeeOther         = 303 // RFC 7231, 6.4.4
        StatusNotModified      = 304 // RFC 7232, 4.1
        StatusUseProxy         = 305 // RFC 7231, 6.4.5

        StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
        StatusPermanentRedirect = 308 // RFC 7538, 3

        StatusBadRequest                   = 400 // RFC 7231, 6.5.1
        StatusUnauthorized                 = 401 // RFC 7235, 3.1
        StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
        StatusForbidden                    = 403 // RFC 7231, 6.5.3
        StatusNotFound                     = 404 // RFC 7231, 6.5.4
        StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
        StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
        StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
        StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
        StatusConflict                     = 409 // RFC 7231, 6.5.8
        StatusGone                         = 410 // RFC 7231, 6.5.9
        StatusLengthRequired               = 411 // RFC 7231, 6.5.10
        StatusPreconditionFailed           = 412 // RFC 7232, 4.2
        StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
        StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
        StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
        StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
        StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
        StatusTeapot                       = 418 // RFC 7168, 2.3.3
        StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
        StatusLocked                       = 423 // RFC 4918, 11.3
        StatusFailedDependency             = 424 // RFC 4918, 11.4
        StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
        StatusPreconditionRequired         = 428 // RFC 6585, 3
        StatusTooManyRequests              = 429 // RFC 6585, 4
        StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
        StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

        StatusInternalServerError           = 500 // RFC 7231, 6.6.1
        StatusNotImplemented                = 501 // RFC 7231, 6.6.2
        StatusBadGateway                    = 502 // RFC 7231, 6.6.3
        StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
        StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
        StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
        StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
        StatusInsufficientStorage           = 507 // RFC 4918, 11.5
        StatusLoopDetected                  = 508 // RFC 5842, 7.2
        StatusNotExtended                   = 510 // RFC 2774, 7
        StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

const DefaultMaxHeaderBytes = 1 << 20 //2的20次方bytes=1048576=1M

const DefaultMaxIdleConnsPerHost = 2

const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"

客户端相关:

type Client
    func (c *Client) Do(req *Request) (*Response, error)
    func (c *Client) Get(url string) (resp *Response, err error)
    func (c *Client) Head(url string) (resp *Response, err error)
    func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error)
    func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)
    
type Request
    func NewRequest(method, url string, body io.Reader) (*Request, error)
    func ReadRequest(b *bufio.Reader) (*Request, error)
    func (r *Request) AddCookie(c *Cookie)
    func (r *Request) BasicAuth() (username, password string, ok bool)
    func (r *Request) Context() context.Context
    func (r *Request) Cookie(name string) (*Cookie, error)
    func (r *Request) Cookies() []*Cookie
    func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)
    func (r *Request) FormValue(key string) string
    func (r *Request) MultipartReader() (*multipart.Reader, error)
    func (r *Request) ParseForm() error
    func (r *Request) ParseMultipartForm(maxMemory int64) error
    func (r *Request) PostFormValue(key string) string
    func (r *Request) ProtoAtLeast(major, minor int) bool
    func (r *Request) Referer() string
    func (r *Request) SetBasicAuth(username, password string)
    func (r *Request) UserAgent() string
    func (r *Request) WithContext(ctx context.Context) *Request
    func (r *Request) Write(w io.Writer) error
    func (r *Request) WriteProxy(w io.Writer) error

服务端相关方法:

func Redirect(w ResponseWriter, r *Request, url string, code int)
func Serve(l net.Listener, handler Handler) error

func Handle(pattern string, handler Handler)
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func ListenAndServe(addr string, handler Handler) error
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error


type Handler
    func FileServer(root FileSystem) Handler
    func NotFoundHandler() Handler
    func RedirectHandler(url string, code int) Handler
    func StripPrefix(prefix string, h Handler) Handler
    func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler
type HandlerFunc
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)

type Response
    func Get(url string) (resp *Response, err error)
    func Head(url string) (resp *Response, err error)
    func Post(url string, contentType string, body io.Reader) (resp *Response, err error)
    func PostForm(url string, data url.Values) (resp *Response, err error)
    func ReadResponse(r *bufio.Reader, req *Request) (*Response, error)
    func (r *Response) Cookies() []*Cookie
    func (r *Response) Location() (*url.URL, error)
    func (r *Response) ProtoAtLeast(major, minor int) bool
    func (r *Response) Write(w io.Writer) error
type ResponseWriter
type RoundTripper
    func NewFileTransport(fs FileSystem) RoundTripper
type ServeMux
    func NewServeMux() *ServeMux
    func (mux *ServeMux) Handle(pattern string, handler Handler)
    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
    func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)
    func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)
type Server
    func (srv *Server) Close() error
    func (srv *Server) ListenAndServe() error
    func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error
    func (srv *Server) RegisterOnShutdown(f func())
    func (srv *Server) Serve(l net.Listener) error
    func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error
    func (srv *Server) SetKeepAlivesEnabled(v bool)
    func (srv *Server) Shutdown(ctx context.Context) error
type Transport
    func (t *Transport) CancelRequest(req *Request)
    func (t *Transport) CloseIdleConnections()
    func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper)
    func (t *Transport) RoundTrip(req *Request) (*Response, error)

客户端请求

常用的就是POSTGET请求以及DELETE

服务端构造请求

//在TCP网络中监听一个地址,然后根据默认的handler去调用`Serve`来处理已经介入的请求。默认开启了TCP的keep-alives,Handler通常都是nil,使用DefaultServeMux的值。
func ListenAndServe(addr string, handler Handler) error


示例代码:
package main

import (
    "io"
    "net/http"
    "log"
)

// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "hello, world!\n")
}

func main() {
    http.HandleFunc("/hello", HelloServer)
    log.Fatal(http.ListenAndServe(":12345", nil))
}

//返回404的请求
func NotFound(w ResponseWriter, r *Request)

//返回重定向目的url的请求,该请求路径应该和请求的路径相关
func Redirect(w ResponseWriter, r *Request, url string, code int)

// Serve接收通过l进来的Http连接,并为每个连接创建一个新的goroutinefu服务。该服务读取请求然后调用handler去返回他们。
func Serve(l net.Listener, handler Handler) error



客户端相关方法

// 增加一个`Set-Cookie`的header去提供ResponseWriter's 的headers。提供的cookie必须是一个有效的Name
func SetCookie(w ResponseWriter, cookie *Cookie)

// 返回HTTP状态码的文本格式,如果code未知,返回空字符
func StatusText(code int) string

// 客户端类型
// Client是一个HTTP客户端,它的零值(DefaultClient)是一个使用`DefaultTransport`的可用客户端
/*
Client的Transport通常都是一个内部的状态(缓存TCP链接),因此Clients应该被多次重新复用而不是在需要的时候再去创建。Clients的相关方法在多个goroutines并发时是非常安全的。

Client比`RoundTripper`(类似Transport)要高级一些,并且有额外的一些handles,比如cookies和redirects。

需要注意的是,当使用重定向(redirects)的时候,客户端将转发内部的请求中包含所有请求头(headers):
- 当转发敏感头文件比如"Authorization", "WWW-Authenticate", and "Cookie”到不被信任的目的时,这些头在重定向到其他域名(不是子域匹配或者初始域名的精确匹配)的时候将被忽略。比如一个重定向从”foo.com”到“foo.com”或者”sub.foo.com”将会转发敏感头,但是重定向到”bar.com”就不会转发了
- 当转发一个非空的cookie Jar头”Cookie”,因为每个重定向可能会改变cookie jar的状态,因此一个重定向可能会在内部的请求中修改cookie集合。当转发”Cookie”头的时候,任何变化的cookie将被忽略,期望的是该Jar能用更新的值来插入到这些变化的cookie中。如果Jar为空,内部cookie将原封不动的转发过去。

*/

type Client struct{
    Transport RoundTripper
    CheckRedirect func(req *Request, via []*Request) error
    Jar CookieJar
    Timeout time.Duration
    
}


// Do发送一个HTTP请求并返回一个HTTP相应和相关错误信息,一些相关的策略比如重定向,cookie,auth需要再客户端中进行配置
// 如果返回的error为nil,则响应中将包含非空的Body,该body是用户主动关闭。如果Body没有被关闭,客户端潜在的RoundTripper(通常为Transport)可能不会重新使用持久的TCP连接去和服务端进行随后的”keep-alive”请求。
// 不过一般来说,会使用Get,Post或者PostForm去代替Do

func (c *Client) Do(req *Request) (*Response, error)


// 如果响应是如下重定向代码中的其中之一,Get方法将在调用Client的CheckRedirect之后进行重定向。

301 (Moved Permanently)
302 (Found)
303 (See Other)
307 (Temporary Redirect)
308 (Permanent Redirect)

// 当err为nil,响应将包含一个非空的resp.Body. Caller应该在从Body中读取完成之后主动关闭resp.Body
// 如果需要自定义headers来构造请求,需要使用NewRequest和Client.Do

func (c *Client) Get(url string) (resp *Response, err error)



// 当从resp中读取完成之后Caller应该主动关闭resp.Body,如果提供的body是一个io.Closer,它将会在请求之后关闭。
// 如果需要自定义headers,需要使用NewRequest和Client.Do

func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error)

// PostForm也是指定URL发起POST请求,但是需要携带URL编码的data的键值作为请求体(request body)
//  Content-type 头被设置为”application/x-www-form-urlencoded”,如果设置其他头,还是需要使用NewRequest和DefaultClient.Do

func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)

几个比较重要的结构体

// Request结构体
type Request struct {
    Method string
    URL *url.URL
    Proto      string // "HTTP/1.0"
    ProtoMajor int    // 1
     ProtoMinor int    // 0
    Header Header
    Body io.ReadCloser
    GetBody func() (io.ReadCloser, error)
    ContentLength int64
    TransferEncoding []string
    Close bool
    Host string
    Form url.Values
    PostForm url.Values
    MultipartForm *multipart.Form
    Trailer Header
    RemoteAddr string
    RequestURI string
    TLS *tls.ConnectionState
    Cancel <-chan struct{}
    Response *Response
    
    

}

// 指定方法,URL,可选的body来构造一个新的请求。
// NewRequest返回的请求适用于Client.Do或者Transport.RoundTrip

func NewRequest(method, url string, body io.Reader) (*Request, error)

// 返回客户端的UA
func (r *Request) UserAgent() string



// Response表示从一个HTTP请求中的响应

type Response struct {
    Status  string      //“200 ok”
    StatusCode  int     // 200
    Proto       string      // “http/1.0”
    ProtoMajor  int     // 1
    ProtoMinor  int     // 0
    Header  Header  
    Body        io.ReadCloser
    ContentLength   int64 
    TransferEncoding    []string
    Close       bool
    Uncompressed    bool
    Trailer Header
    Request *Request
    TLS     *tls.ConnectionsState

}


// 如果返回码是3开头的,会直接去重定向,最大重定向次数为10
// Get是包装的DefaultClient.Get方法。如果要使用自定义headers,需要使用NewRequest和DefaultClient.Do
func Get(url string) (res *Response,err error)

测试示例:
res,err := http.Get(“http://www.baidu.com”)
if err != nil { fmt.Errorf(“error %s”,err.Error()) }
content, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil { fmt.Errorf(“error %s”,err.Error()) }
fmt.Println(content)


// 
func Post(url string, contentType string, body io.Reader) (resp *Response, err error)


// 是DefaultClient.PostForm的包装函数。默认Content-Type被设置为”application/x-www-form-urlencoded”
func PostForm(url string, data url.Values) (resp *Response, err error)



// ServeMux用来定义HTTP的请求URI定义器。默认为空的结构体
type ServeMux {
}

// 初始化Mux
func NewServeMux() *ServeMux

// Handle 用来注册一个指定模式的handler,如果已经存在则panic
func (mix *ServeMux) Handle(pattern string, handler Handler)

示例:
mux := http.NewServeMux()
mux.Handle("/api/", apiHandler{})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        // The "/" pattern matches everything, so we need to check
        // that we're at the root here.
        if req.URL.Path != "/" {
                http.NotFound(w, req)
                return
        }
        fmt.Fprintf(w, "Welcome to the home page!")
})


// HandleFunc 给指定的模式注册一个handler 函数
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))


// Handler 给指定请求返回一个handler,包含r.Method,r.Host,r.URL.Path 总是返回一个非空的handler。如果host包含一个port,当匹配handlers的时候将会被忽略。如果没有注册到的handler给请求使用,handler将返回”page not found” handler并且返回一个空的模式匹配
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)

// ServeHTTP调度请求给匹配到的handler
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)



// Server 结构体为运行的HTTP Server定义了一系列的变量,Server的零值是一个有效的配置

type Server struct {
    Addr        string
    Handler Handler
    TLSConfig   *tls.Config
    ReadTimeout time.Duration
    ReadHeaderTimeout   time.Duration
    WriteTimeout    time.Duration
    IdleTimeout     time.Duration
    MaxHeaderBytes  int
    TLSNextProti    map[string]func(*Server,*tls.Conn,Handler)
    ConnState       func(net.Conn,ConnState)
    ErrorLog        *log.Logger
}

// Close 方法会立即关闭所有活动状态的net.Listeners和StateNew,StateActive,Stateldle状态的所有连接。如果想要优雅关停服务的话,需要使用Shutdown
// Close不会去尝试关闭任何劫持的连接,比如WebSockets
func (src *Server) Close() error


// 监听一个TCP网络的地址srv.Addr 然后调用Serve去处理连接请求。所有被接收的连接会被配置为开启TCP的keep-alives,如果srv.Addr为空,” :http”将被使用
func (src *Server) ListenAndServe() error


// Serve 接收Listener l 中的连接,为每一个连接创建一个新的goroutine的service,该service回去读取请求之后调用srv.Handler去响应 
func (srv *Server) Serve(l net.Listener) error

// 优雅关停http服务器
func (srv *Server) Shutdown(ctx context.Context) error




// Transport结构体是RoundTripper中的一个工具,当前支持HTTP/(S),以及HTTP代理
// 默认Transport会缓存链接状态,以便未来重新使用链接。
type Transport struct {
    Proxy       func(*Request)  (*url.URL,error)
    DialContext func(ctx context.Context,network,addr string)  (net.Conn,error)
    Dial        func(network,addr string) (net.Conn,error)
    DialTLS func(network,addr string) (net.Conn,error)
    TLSClientConfig *tls.Config
    DisableKeepAlives   bool
    DisableCompression  bool
    MaxIdleConns        int
    MaxIdleConnsPerHost int
    IdleConnTimeout     time.Duration
    ResponseHeaderTimeout   time.Duration
    ExpectContinueTimeout   time.Duration
    TLSNextProto        map[string] func(authority string, c *tls.Conn) RoundTripper
    ProxyConnectHeader  Header
    MaxResponseHeaderBytes  int64
}







上一篇 下一篇

猜你喜欢

热点阅读