Go pkg学与练 - http

Stanley · 2018-04-10 16:45:57 · 1505 次点击 · 预计阅读时间 13 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2018-04-10 16:45:57 的文章,其中的信息可能已经有所发展或是发生改变。

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) {

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1505 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传