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")
Clients
和Transports
在多个goroutines在并发使用的时候是比较安全的,而且为了效率,应该创建一次重复使用。
ListenAndServe
根据指定的地址和handler来启动一个http server.一般来说,这个handler通常会设置为nil
,这意味着使用默认的DefaultServeMux
.Handle
和HandleFunc
用来增加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包的Transport
和Server
都自动开启了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)
客户端请求
常用的就是POST
和GET
请求以及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
}