
标准库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) }