Go http package 包含了http client 和 http server 的实现。主要文件有:
~~~
client.go
cookie.go
header.go
http.go
method.go
request.go
response.go
server.go
transport.go
~~~
Server.go:
---------
我们先从一个简单的http server开始。创建一个http服务需要有三个步骤:
* 创建ServerMux:将预定义的url列表与Hanlder相关联。
* 创建Handler:负责对http请求进行处理,返回http响应。
* 监听给定的地址及端口提供http服务。
~~~
package main
import (
"fmt"
"html"
"log"
"net/http"
)
func fooHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
func main() {
mux := http.NewServeMux()
handler := http.HandlerFunc(fooHandler)
mux.Handle("/foo", handler)
log.Fatal(http.ListenAndServe(":8080", mux))
}
~~~
ServeMux:
~~~
// ServeMux 结构
type ServeMux struct {
mu sync.RWMutex
// 这个map用于存放http url entries, 而每个erntry 包含了一个Handler
// 对应上面的例子:m = {"/foo":fooHandler(ResponseWriter, *Request)}
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
explicit bool
h Handler
pattern string
}
func NewServeMux() *ServeMux { return new(ServeMux) }
func (mux *ServeMux) match(path string) (h Handler, pattern string) {
// 根据request找出对应的Handler
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
// 将request 分发给Handler处理
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
// 注册Handler
func (mux *ServeMux) Handle(pattern string, handler Handler) {
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
~~~
DefaultServeMux:
~~~
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
// 上面的例子用defaultServeMux,可以简化为:
func main() {
handler := http.HandlerFunc(fooHandler)
http.Handle("/foo", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
或者
func main() {
http.HandleFunc("/foo", fooHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
~~~
Handler:
~~~
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// f 实现接口 Handler ServeHTTP
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
// 已定义好的一些处理器
func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
func RedirectHandler(url string, code int) Handler {
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
~~~
ListenAndServe:
~~~
// server 结构
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil
TLSConfig *tls.Config // optional TLS config, used by ServeTLS and ListenAndServeTLS
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
disableKeepAlives int32 // accessed atomically.
inShutdown int32 // accessed atomically (non-zero means we're in Shutdown)
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used
mu sync.Mutex
listeners map[net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan chan struct{}
onShutdown []func()
}
// 创建Server,调用ListenAndServe
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServeTLS(certFile, keyFile)
}
// 调用net.Listen()进行监听
func (srv *Server) ListenAndServe() error {
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
// 接着调用server.Serve负责处理请求
func (srv *Server) Serve(l net.Listener) error {
func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error {
// Serve()调用Accept获取连接数据, 并创建conn, go c.serve()处理请求
func (srv *Server) newConn(rwc net.Conn) *conn {
/* conn 结构
type conn struct {
server *Server
cancelCtx context.CancelFunc
rwc net.Conn
remoteAddr string
tlsState *tls.ConnectionState
werr error
r *connReader
bufr *bufio.Reader
bufw *bufio.Writer
lastMethod string
curReq atomic.Value // of *response (which has a Request in it)
curState atomic.Value // of ConnState
mu sync.Mutex
hijackedv bool
}*/
// c.readRequest()读取请求, 调用Handler ServeHTTP()
func (c *conn) serve(ctx context.Context) {
Server中其他methods:
func (srv *Server) maxHeaderBytes() int {
func (srv *Server) initialReadLimitSize() int64 {
func (srv *Server) Close() error {
func (srv *Server) Shutdown(ctx context.Context) error {
func (srv *Server) RegisterOnShutdown(f func()) {
func (srv *Server) shouldConfigureHTTP2ForServe() bool {
func (srv *Server) SetKeepAlivesEnabled(v bool) {
func (srv *Server) setupHTTP2_ServeTLS() error {
func (srv *Server) setupHTTP2_Serve() error {
func (srv *Server) onceSetNextProtoDefaults_Serve() {
func (srv *Server) onceSetNextProtoDefaults() {
Conn中其他methods:
func (c *conn) hijacked() bool {
func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
func (c *conn) finalFlush() {
func (c *conn) close() {
func (c *conn) closeWriteAndWait() {
func (c *conn) setState(nc net.Conn, state ConnState) {
func (c *conn) serve(ctx context.Context) {
~~~
ResponseWrite:
~~~
type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(int)
}
// response struct 实现 http.ResponseWriter
type response struct {
conn *conn
req *Request // request for this response
reqBody io.ReadCloser
cancelCtx context.CancelFunc // when ServeHTTP exits
wroteHeader bool // reply header has been (logically) written
wroteContinue bool // 100 Continue response was written
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
wantsClose bool // HTTP request has Connection "close"
// 例子中的字符串“hello ...”会写在w中
w *bufio.Writer // buffers output in chunks to chunkWriter
cw chunkWriter
handlerHeader Header
calledHeader bool // handler accessed handlerHeader via Header
// 对应字符串长度
written int64 // number of bytes written in body
contentLength int64 // explicitly-declared Content-Length; or -1
// 状态码
status int // status code passed to WriteHeader
closeAfterReply bool
requestBodyLimitHit bool
trailers []string
handlerDone atomicBool // set true when the handler exits
dateBuf [len(TimeFormat)]byte
clenBuf [10]byte
statusBuf [3]byte
closeNotifyCh chan bool
didCloseNotify int32 // atomic (only 0->1 winner should send)
}
func (w *response) Header() Header {
func (w *response) Write(data []byte) (n int, err error) {
func (w *response) WriteHeader(code int) {
~~~
Client.go:
---------
客户端可以直接使用http.Get, http.Post等,示例如下:
~~~
package main
import "net/http"
import "fmt"
import "io/ioutil"
func main() {
resp, err := http.Get("http://www.163.com")
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
~~~
~~~
func Get(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 Head(url string) (resp *Response, err error) {
func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
// 可以通过创建Client来做某些控制
type Client struct {
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
Timeout time.Duration
}
func (c *Client) Get(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) {
func (c *Client) Head(url string) (resp *Response, err error) {
func (c *Client) Do(req *Request) (*Response, error) {
func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
~~~
Request.go
----------
~~~
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
ctx context.Context
}
func NewRequest(method, url string, body io.Reader) (*Request, error) {
func (r *Request) Context() context.Context {
func (r *Request) WithContext(ctx context.Context) *Request {
func (r *Request) ProtoAtLeast(major, minor int) bool {
func (r *Request) UserAgent() string {
func (r *Request) Cookies() []*Cookie {
func (r *Request) Cookie(name string) (*Cookie, error) {
func (r *Request) AddCookie(c *Cookie) {
func (r *Request) Referer() string {
func (r *Request) MultipartReader() (*multipart.Reader, error) {
func (r *Request) multipartReader() (*multipart.Reader, error) {
func (r *Request) isH2Upgrade() bool {
func (r *Request) Write(w io.Writer) error {
func (r *Request) WriteProxy(w io.Writer) error {
func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) (err error) {
func (r *Request) BasicAuth() (username, password string, ok bool) {
func (r *Request) SetBasicAuth(username, password string) {
func (r *Request) ParseForm() error {
func (r *Request) ParseMultipartForm(maxMemory int64) error {
func (r *Request) FormValue(key string) string {
func (r *Request) PostFormValue(key string) string {
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
func (r *Request) expectsContinue() bool {
func (r *Request) wantsHttp10KeepAlive() bool {
func (r *Request) wantsClose() bool {
func (r *Request) closeBody() {
func (r *Request) isReplayable() bool {
func (r *Request) outgoingLength() int64 {
~~~
Response.go
-----------
~~~
type Response struct {
Status string // e.g. "200 OK"
StatusCode int // e.g. 200
Proto string // e.g. "HTTP/1.0"
ProtoMajor int // e.g. 1
ProtoMinor int // e.g. 0
Header Header
Body io.ReadCloser
ContentLength int64
TransferEncoding []string
Close bool
Uncompressed bool
Trailer Header
Request *Request
TLS *tls.ConnectionState
}
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 {
func (r *Response) closeBody() {
func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
~~~
有疑问加站长微信联系(非本文作者))