【Golang】网络开发:http开发

经过上一篇的net/http包,来实现一个简单的demo

服务端

创建监听

通过上一篇的包阅读可以看到,http监听服务端有两种办法:

  1. 直接使用http.ListenAndServe(addr string, handler Handler)开启一个默认的监听服务器
	http.HandleFunc("/", enterHander)
	err := http.ListenAndServe(ip+":"+port, nil)
  1. 先实例化一个http.server,配置结构体参数后使用func (srv *Server) ListenAndServe() error监听
	server := http.Server{
		Addr: ip + ":" + port,
		...
	}
	err := server.ListenAndServe()

设置回调

根据文档,server的回调是使用ServeMux作为处理器,如果在监听的时候不传回使用默认的DefaultServeMux。处理数据的具体函数可以使用HandleHandleFunc方法

ListenAndServe使用指定的监听地址和处理器启动一个HTTP服务端。处理器参数通常是nil,这表示采用包变量DefaultServeMux作为处理器。Handle和HandleFunc函数可以向DefaultServeMux添加处理器。

使用默认的DefaultServeMux注册回调

func Handle(pattern string, handler Handler)

Handle注册HTTP处理器handler和对应的模式pattern(注册到DefaultServeMux)。如果该模式已经注册有一个处理器,Handle会panic。ServeMux的文档解释了模式的匹配机制。

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

HandleFunc注册一个处理器函数handler和对应的模式pattern(注册到DefaultServeMux)。ServeMux的文档解释了模式的匹配机制。

http包内自带给默认的DefaultServeMux注册回调的方法,这里以匿名函数为例

	http.HandleFunc("/", func (res http.ResponseWriter, req *http.Request) {
		n, err := res.Write([]byte("enterHander"))
		if err != nil {
			log.Println(err)
		}
		log.Println(n)
	})

注册完后,监听的服务端会根据路由自动回调处理。

使用自定义的ServeMux注册回调

同样的,自定义的ServeMux内也有一样的注册方法

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))

HandleFunc注册一个处理器函数handler和对应的模式pattern。

结合起来使用

func HttpServer(ip string, port string) {
	// 默认的回调输出default
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		n, err := res.Write([]byte("default"))
		if err != nil {
			log.Println(err)
		}
		log.Println(n)
	})
	// 自定义一个ServeMux
	serverMux := http.NewServeMux()
	serverMux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		n, err := res.Write([]byte("no default"))
		if err != nil {
			log.Println(err)
		}
		log.Println(n)
	})

	wg.Add(2)
	// 起个协程监听9900,用默认处理
	go func() {
		err := http.ListenAndServe("0.0.0.0:9900", nil)
		if err != nil {
			log.Println(err)
		}
		defer wg.Done()
	}()

	// 起个协程监听9901,用自定义处理器
	go func() {
		err := http.ListenAndServe("0.0.0.0:9901", serverMux)
		if err != nil {
			log.Println(err)
		}
		defer wg.Done()
	}()

	wg.Wait()
}

命令行

C:\project
λ curl 127.0.0.1:9900
default
C:\project
λ curl 127.0.0.1:9901
no default

客户端

使用go的http客户端发送请求也非常简单

自定义和默认客户端

可以使用go默认的客户端发送请求,有以下几个方法

  1. func Head(url string) (resp *Response, err error) Head向指定的URL发出一个HEAD请求,如果回应的状态码如下,Head会在调用c.CheckRedirect后执行重定向

  2. func Get(url string) (resp *Response, err error) Get向指定的URL发出一个GET请求,如果回应的状态码如下,Get会在调用c.CheckRedirect后执行重定向 如果c.CheckRedirect执行失败或存在HTTP协议错误时,本方法将返回该错误;如果回应的状态码不是2xx,本方法并不会返回错误。如果返回值err为nil,resp.Body总是非nil的,调用者应该在读取完resp.Body后关闭它。 Get是对包变量DefaultClient的Get方法的包装。

  3. func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) Post向指定的URL发出一个POST请求。bodyType为POST数据的类型, body为POST数据,作为请求的主体。如果参数body实现了io.Closer接口,它会在发送请求后被关闭。调用者有责任在读取完返回值resp的主体后关闭它。 Post是对包变量DefaultClient的Post方法的包装。

  4. func PostForm(url string, data url.Values) (resp *Response, err error) PostForm向指定的URL发出一个POST请求,url.Values类型的data会被编码为请求的主体。如果返回值err为nil,resp.Body总是非nil的,调用者应该在读取完resp.Body后关闭它。 PostForm是对包变量DefaultClient的PostForm方法的包装。

使用自定义的客户端net.Client

  1. func (c *Client) Do(req *Request) (resp *Response, err error) Do方法发送请求,返回HTTP回复。它会遵守客户端c设置的策略(如重定向、cookie、认证)。 如果客户端的策略(如重定向)返回错误或存在HTTP协议错误时,本方法将返回该错误;如果回应的状态码不是2xx,本方法并不会返回错误。 如果返回值err为nil,resp.Body总是非nil的,调用者应该在读取完resp.Body后关闭它。如果返回值resp的主体未关闭,c下层的RoundTripper接口(一般为Transport类型)可能无法重用resp主体下层保持的TCP连接去执行之后的请求。 请求的主体,如果非nil,会在执行后被c.Transport关闭,即使出现错误。 一般应使用Get、Post或PostForm方法代替Do方法。

  2. func (c *Client) Head(url string) (resp *Response, err error) Head向指定的URL发出一个HEAD请求,如果回应的状态码如下,Head会在调用c.CheckRedirect后执行重定向

  3. func (c *Client) Get(url string) (resp *Response, err error) Get向指定的URL发出一个GET请求,如果回应的状态码如下,Get会在调用c.CheckRedirect后执行重定向: 如果c.CheckRedirect执行失败或存在HTTP协议错误时,本方法将返回该错误;如果回应的状态码不是2xx,本方法并不会返回错误。如果返回值err为nil,resp.Body总是非nil的,调用者应该在读取完resp.Body后关闭它。

  4. func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) Post向指定的URL发出一个POST请求。bodyType为POST数据的类型, body为POST数据,作为请求的主体。如果参数body实现了io.Closer接口,它会在发送请求后被关闭。调用者有责任在读取完返回值resp的主体后关闭它。

  5. func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) PostForm向指定的URL发出一个POST请求,url.Values类型的data会被编码为请求的主体。POST数据的类型一般会设为"application/x-www-form-urlencoded"。如果返回值err为nil,resp.Body总是非nil的,调用者应该在读取完resp.Body后关闭它。

url.Values

type Values map[string][]string

Values maps a string key to a list of values. It is typically used for query parameters and form values. Unlike in the http.Header map, the keys in a Values map are case-sensitive.

  1. 这是一个kv结构的map

func ParseQuery(query string) (Values, error)

ParseQuery parses the URL-encoded query string and returns a map listing the values specified for each key. ParseQuery always returns a non-nil map containing all the valid query parameters found; err describes the first decoding error encountered, if any.

  1. 使用ParseQuery将参数转为URL-encoded query string
  2. {"x":["1"], "y":["2", "3"], "z":[""]}

func (v Values) Add(key, value string)

Add adds the value to key. It appends to any existing values associated with key.

  1. 增加一个键值对,如果键已存在会跟在原来的值后面(是个[]string)

func (v Values) Del(key string)

Del deletes the values associated with key.

  1. 删除一个key

func (v Values) Encode() string

Encode encodes the values into “URL encoded” form ("bar=baz&foo=quux") sorted by key.

  1. 变为urlencode格式,上面有demo

func (v Values) Get(key string) string

Get gets the first value associated with the given key. If there are no values associated with the key, Get returns the empty string. To access multiple values, use the map directly.

  1. 取这个键上的第一个值
  2. To access multiple values, use the map directly.要取多个还是得按map来

func (v Values) Set(key, value string)

Set sets the key to value. It replaces any existing values.

  1. 和add不同的是,这个会直接替代原有的值

实际操作一下

这个就非常简单了,get请求就先跳过直接发post吧

func HtpClient() {
	client := http.Client{}
	param := url.Values{}
	param.Add("k", "v")
	res, err := client.PostForm("http://noobcoder.cn", param)
	if err != nil {
		log.Println("err:", err)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println("err", err)
	}
	log.Println(string(body))
}

要注意的是,这个http.response.bodyio.ReadCloser类型的值

小结

golang-网络编程

程序幼儿员-龚学鹏
请先登录后发表评论
  • latest comments
  • 总共0条评论