命令记不住

登陆

标准库 net/http

标准库net/http

HTTP中最重要的四个部分,http Request、http Response、http Client、http Server

1.http.Get

http.Get函数产生一个http请求,返回结果存在相应结构resp里面

func main() {
	for _, url := range os.Args[1:] {
		resp, err := http.Get(url)
		if err != nil {
			fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
			os.Exit(1)
		}
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Fprint(os.Stderr, "fetch:reading %s: %v\n", url, err)
			os.Exit(1)
		}
		fmt.Printf("%s\n", b)
	}
}

2.http.HandleFunc

运行多个路由,handler

func main() {
	http.HandleFunc("/", handler)
	http.HandleFunc("/count", counter)
	log.Fatal(http.ListenAndServe("127.0.0.1:8001", nil))

}

func handler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	count++
	mu.Unlock()
	fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}

func counter(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	fmt.Fprintf(w, "Count %d\n", count)
	mu.Unlock()
}

3.http Request相关的方法

request.go

//利用指定的method,url以及可选的body返回一个新的请求,如果body参数实现了io.Closer接口,Request返回的Body字段会被设置为body,并会被Client类型的
//Do、Post和PostForm方法以及Transport.RoundTrip方法关闭
func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

//从b中读取和解析一个请求
func ReadRequest(b *bufio.Reader) (req *Request, err error)

//给request添加cookie,AddCookie向请求中添加一个cool=kie,按照RFC 6265 section 5.4的规则,AddCookie不会添加超过一个Cookie头字段
//这表示所有的Cookie都写在同一行,用分号分割(cookie内部用逗号分割属性)
func (r *Request) AddCookie(c *Cookie)

//返回request中指定名name的cookie,如果没有发现,返回ErrNoCookie
func (r *Request) Cookie(name string) (*Cookie, error)

//返回该请求的锁头Cookie
func (r *Request) Cookies() []*Cookie

//利用提供的用户名和密码给http基本权限提供具有一定权限的header
//当http基本授权时,用户名和密码是不加密的
func (r *Request) SetBaseAuth(username, password string)

//如果在request中发送,该函数返回客户端的user-Agent
func (r *Request) UserAgent() string

//对于指定格式的key,FormFile返回符合条件的第一个文件,如果有必要的话,该函数会调用ParseMulitpartForm和PaseForm.
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)

//返回key获取的队列中第一个值,在查询过程中post和put中的主题参数优先级高于url中的value,为了访问相同key的多个值,嗲偶哦那个PaseForm然后
//直接检查RequestForm
func (r *Request) FormValue(key string) string

//如果这是一个由多部分组成的post请求,该函数将会返回一个多部分的reader,否则返回一个nil和error。使用本函数代替ParseMultipartForm
//可以将请求body当作流stream来处理
func (r *Request) Multiparteader() (*multipart.Reader, error)

//解析URL中的查询字符串,并将解析结果更新到r.Form字段。对于POST或PUT请求,ParseForm还会将body当作表达解析,并将结果既更新到r.PostForm也
//更新到r.Form。解析结果中,POST或PUT请求主体要有限于URL查询字符串(同名变量,主体的值在查询字符串的值前面),如果
//请求的主体大小没有被MaxBytesReader函数设定限制,其大小默认限制为开头10MB
//ParseMultipartForm会自动调用ParseForm.重复调用本方法是无意义的
func (r *Request) ParseForm() error

//ParseMutiparForm将请求的主体作为multipart/form-data解析
//请求的整个主体都会被解析,得到的文件记录最多有maxMermery字节保存在内存,其余部分保存
//在硬盘temp文件里。如果必要,ParseMultiparForm会自行调用ParseForm.重复调用本方法是无意义的
func (r *Request) ParseMultipartForm(maxMemory int64) error

//返回post或者put请求body指定元素的第一个值,其中的参数被忽略
func (r *Reuest) PostFormValue(key string) string

//检测在request中使用的http协议是否至少是major.minor
func (r *Request) ProAtLeast(major, minor int) bool

//如果request中有refer,那么refer返回相应的url。Referer在request中是拼错的,这个错误从http初期就已经存在了。该值
//也可以从Headermap中利用Header["Referer"]获取;在使用过程中利用Referer这个方法而不是mao的形式的好处是在编译过程中可以检查方法的错误
//而无法检查mao中key的错误
func (r *Request) Referer() string

//Write方法以线性格式将HTTP/1.1请求写入W(用于将请求写入下层TCPConn等)
func (r *Request)Write(w io.Writer)error

//该函数与Write方法类似,但是该方法写的request是按照http代理的格式去写
//尤其是按照RFC 2616 Section 5.1.2,WriteProxy会使用绝对URL(包括协议和主机名)来
//初始化请求的第1行(Request-URL行)。无论何种情况,WriteProxy都会使用r.Host或r.URL.Host设置Host头
func (r *Request)WriteProxy(w io.Writer)error

4.http Response相关的方法

http Response是由http Server发出的消息,用来响应http Client发出的http Request请求,发出的消息包括起始行、Headers和Body

//ReadResponse从r读取并返回一个HTTP回复,req参数是可选的,指定该回复对应的请求(既对该请求的回复),如果是Nil,将假设请求是GET请求
//客户端必须在结束resp.Body的读取后后关闭它,读取完毕并关闭后,客户端可以检查resp.Trailer字段获取回复的trailer的键值对
func ReadResponse(r *bufio.Reader,req *Request)(*Response,error)

//解析cooke并返回在header中利用set-Cookie设定的cookie值
func (r *Response)Cookies()[]*Cookie 

//返回response中Location的header值的url,如果该值存在的话,则对于请求问题可以解决相对重定向的问题
//如果该值为Nil,则返回ErrNOLocation
func (r *Response)Location()(*url.URL,error)

//判断在response中使用的http协议是否至少是major.minor的形式
func (r *http.Response)ProtoAtLease(major,minor int)bool 

//将response中信息按照线性格式写入w中
func (r *Response)Write(w io.Writer)error

5.http Client相关的方法

http Client客户端主要用来发送http Request给http Server服务端。

Client具有Do,Get,Head,Post以及PostForm等方法。其中Do方法可以对Request进行一系列的设定,而其他方法对request设定较少,如果客户端使用默认的Client,则其中的Get,Head,Post以及PostForm方法相当于默认的http.Get

//利用GET方法对一个指定的URL进行请求,如果response是如下重定向中的一个代码,则Get之后将会调用重定向内容,最多10次重定向
//301   永久重定向
//302   暂时性重定向
//303   (对于Post请求,它表示请求已经被处理,客户端可以接着使用GET方法请求Location里的URL)
//307   临时重定向,对于POST请求,表示请求还没有被处理,客户端应该向Location里的URL重新发起Post请求
func Get(url string)(resp *Response,err error)

//该函数功能见net中Head方法的功能。该方法与默认的defaultClient中Head方法一致
func Head(url string)(resp *Response,err error)

//该方法与默认的defaultClient中的Post方法一致
func Post(url string,bodyType string,body io.Reader)(resp *Response,err error)

//该方法与默认的defaultClient中PostForm方法一致
func PostForm(url string,data url.Values)(resp *Response,err error)

//Do发送http请求并且返回一个http响应,遵守client的策略,如重定向、cookies以及auth等,错误经常是由策略硬气的,当err
//是nil时,reso总会包含一个非Nil的resp.body。当调用者读完rtesp.body之后应该关闭它,
//如果resp.body没有关闭,则client底层RoundTripper将无法重用存在的TCP连接去服务接下来的请求,如果resp.body非nil,
//则必须对其进行关闭,通常来说,经常使用Get,Post或者PostForm来替代Do
func (c *Client)Do(req *Request)(resp *Response,err error)

//利用get方法请求指定的url。Get请求指定页面信息,并返回实体主体
func (c *Client)Get(url string)(resp *Response,err error)

//利用head方法请求指定的url,Head只返回页面的首部
func (c *Client)Head(url string)(resp *Response,err error)

//post方法请求指定URL,如果body也是一个io.Closer,则在请求之后关闭它
func (c *Client)Post(url string,bodyType string,body io.Reader)(resp *Response,err error)

//利用post方法请求指定的url,利用data的key和value作为请求体
func (c *Client)PostForm(url string,data url.Values)(resp *Response,err error)
(1)模拟任何http Request请求
func main() {
    // 简式声明一个http.Client空结构体指针对象
    client := &http.Client{}

    // 使用http.NewRequest构建http Request请求
    request, err := http.NewRequest("GET", "http://www.baidu.com", nil)
    if err != nil {
        fmt.Println(err)
    }

    // 使用http.Cookie结构体初始化一个cookie键值对
    cookie := &http.Cookie{Name: "userId", Value: strconv.Itoa(12345)}

    // 使用前面构建的request方法AddCookie往请求中添加cookie
    request.AddCookie(cookie)

    // 设置request的Header,具体可参考http协议
    request.Header.Set("Accept", "text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8")
    request.Header.Set("Accept-Charset", "GBK, utf-8;q=0.7, *;q=0.3")
    request.Header.Set("Accept-Encoding", "gzip, deflate, sdch")
    request.Header.Set("Accept-Language", "zh-CN, zh;q=0.8")
    request.Header.Set("Cache-Control", "max-age=0")
    request.Header.Set("Connection", "keep-alive")

    // 使用http.Client 来发送request,这里使用了Do方法。
    response, err := client.Do(request)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 程序结束时关闭response.Body响应流
    defer response.Body.Close()

    // 接收到的http Response 状态值
    fmt.Println(response.StatusCode)
    if response.StatusCode == 200 { // 200意味成功得到http Server返回的http Response信息

        // gzip.NewReader对压缩的返回信息解压(考虑网络传输量,http Server一般都会对响应压缩后再返回)
        body, err := gzip.NewReader(response.Body)
        if err != nil {
            fmt.Println(err)
        }

        defer body.Close()

        r, err := ioutil.ReadAll(body)
        if err != nil {
            fmt.Println(err)
        }
        // 打印出http Server返回的http Response信息
        fmt.Println(string(r))
    }
}
(2)发送一个http.Get请求
func main() {
    // var DefaultClient = &Client{}
    // func Get(url string) (resp *Response, err error) {
    // return DefaultClient.Get(url)
    // }
    /*
        func (c *Client) Get(url string) (resp *Response, err error) {
            req, err := NewRequest("GET", url, nil)
            if err != nil {
                return nil, err
            }
            return c.Do(req)
        }
    */

    // http.Get实际上是DefaultClient.Get(url),Get函数是高度封装的,只有一个参数url。
    // 对于一般的http Request是可以使用,但是不能定制Request。
    response, err := http.Get("http://www.baidu.com")
    if err != nil {
        fmt.Println(err)
    }

    // 程序在使用完回复后必须关闭回复的主体。
    defer response.Body.Close()

    body, _ := ioutil.ReadAll(response.Body)
    fmt.Println(string(body))
}
(3)发送一个http.Post请求
func main() {
    // application/x-www-form-urlencoded:为POST的contentType
    // strings.NewReader("mobile=xxxxxxxxxx&isRemberPwd=1") 理解为传递的参数
    resp, err := http.Post("http://localhost:8080/login.do",
        "application/x-www-form-urlencoded", strings.NewReader("mobile=xxxxxxxxxx&isRemberPwd=1"))
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(body))
}
(4)发送一个http.PostForm请求
func main() {
    postParam := url.Values{
        "mobile":      {"xxxxxx"},
        "isRemberPwd": {"1"},
    }
    // 数据的键-值会经过URL编码后作为请求的body传递
    resp, err := http.PostForm("http://localhost:8080/login.do", postParam)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(body))
}

上面举例了四种http Client发送http Request的方式,其中Do方法最灵活

6.http Server相关的方法

利用这些方法可以把收到的http Request处理后,以http Response的形式返回给http Client

//监听TCP网络地址srv.Addr然后调用Server来处理接下来连接的请求
//如果srv.Addr是空的话,则使用“:http”
func (srv *Server) ListenAndServe() error

//ListenAndServeTLS监听srv.Addr确定的TCP地址,并且会调用Serve方法处理
//接收到的连接。必须提供证书文件和对应的私钥文件,如果证书是由权威机构签发的,cerFile参数必须是顺序串联的服务端证书
//和CA证书,如果srv.Addr为空字符串,会使用“:http”
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error

//接受Listener1的连接,创建一个新的服务协程,该服务协程读取请求然后调用srv.Handler来应答。实际上就是实现了对某个端口进行监听
//然后创建相应的连接
func (srv *Server)Serve(l net.Listener)error

//该函数控制http的keep-alies是否能够使用,默认情况下,keep-alives总是可用的
//只有资源非常紧张的环境或者服务端在关闭进程中时,才应该关闭该功能
func (s *Server)SetKeepAlivesEnable(v bool)

//是一个http请求多路复用器,它将每一个请求的URL和一个注册模式的
//列表进行匹配,然后调用和URL最匹配的模式处理器进行后续操作
type ServeMux struct 

//初始化一个新的ServeMux
func NewServeMux() *ServeMux 

//将handler注册为指定的模式
func (mux *ServeMux)HandleFunc(pattern string,handler func(ResponseWriter,*Request))

//过呢据指定r.Method、r.Host以及r.URL.Path返回一个用来处理给定请求的handler
//该函数总是返回一个非Nil的handler,如果path不是一个规范模式,则handler会重定向到其规范path
//Handler总是返回匹配该请求的已注册模式,在内建重定向处理器的情况下,pattern会在重定向后
//进行匹配,如果没有已注册模式可以应用与该请求,本方法将返回一个内建的“404 page not found”处理器和一个空字符串模式
func (mux *ServemUX)Handler(r *Request)(h Handler,pattern string)

//该函数用于将最近请求url模式的handler分配给指定的请求
func (mux *ServeMux)ServeHTTP(w ResponseWriter,r *Request)

详细内容有时间了再进行补充

示例:

func myfunc(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "hi")
}

func main() {
    // 更多http.Server的字段可以根据情况初始化
    server := http.Server{
        Addr:         ":8080",
        ReadTimeout:  0,
        WriteTimeout: 0,
    }
    http.HandleFunc("/", myfunc)
    server.ListenAndServe()
}

示例:

func myfunc(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "hi")
}

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/", myfunc)
    http.ListenAndServe(":8080", mux)
}

示例:

func myfunc(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "hi")
}

func main() {
    server := http.Server{
        Addr:         ":8080",
        ReadTimeout:  0,
        WriteTimeout: 0,
    }
    mux := http.NewServeMux()
    server.Handler = mux

    mux.HandleFunc("/", myfunc)
    server.ListenAndServe()
}

示例:

type timeHandler struct {
    format string
}

func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    tm := time.Now().Format(th.format)
    w.Write([]byte("The time is: " + tm))
}

func main() {
    mux := http.NewServeMux()

    th := &timeHandler{format: time.RFC1123}
    mux.Handle("/time", th)

    log.Println("Listening...")
    http.ListenAndServe(":3000", mux)
}

示例:

func timeHandler(w http.ResponseWriter, r *http.Request) {
    tm := time.Now().Format(time.RFC1123)
    w.Write([]byte("The time is: " + tm))
}

func main() {
    mux := http.NewServeMux()

    // 把函数 timeHandler 转为 HandlerFunc
    th := http.HandlerFunc(timeHandler)
    // th作为mux的handler
    mux.Handle("/time", th)

    log.Println("Listening...")
    http.ListenAndServe(":3000", mux)
}

示例:

func main() {
    http.Handle("/", http.FileServer(http.Dir("D:/html/static/")))
    http.ListenAndServe(":8080", nil)
}
推荐阅读