在网络编程里多数情况下,我们都在处理HTTP请求,关于请求协议的部分我推荐阅读《TCP协议》这本书,绝对值得购买。Go语言也提供了一个标准库包net/http,让开发者可以快速的处理HTTP请求,其封装的易用性,足够简单。并且,整个net包里提供了多种多样的处理模块,比如rpc等等。http包提供了HTTP客户端和服务端的实现,这让我想到了Node.js提供的http模块。
简单的Get
response, err := http.Get("http://icepy.me")
if err != nil {
// handle error
}
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(body))
简单的Post
body := "{\"action\":20}"
res, err := http.Post("http://icepy.me", "application/json;charset=utf-8", bytes.NewBuffer([]byte(body)))
if err != nil {
fmt.Println("Fatal error ", err.Error())
}
defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("Fatal error ", err.Error())
}
fmt.Println(string(content))
简单的PostFrom
resp, err := http.PostForm("http://icepy.me",
url.Values{"key": {"Value"}, "id": {"123"}})
if err != nil {// handle error}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {// handle error}
fmt.Println(string(body))
在上述的两个方法中,也就是说Get,Post提供了非常方便的快捷方式来处理,真正的做到了无须关心协议的细节问题,当然如果你想拥有更多的灵活性,那么就要用到http.Client和http.NewRequest了。
v := url.Values{}
v.Set("username", "xxxx")
v.Set("password", "xxxx")
body := ioutil.NopCloser(strings.NewReader(v.Encode()))
client := &http.Client{}
reqest, err := http.NewRequest("POST", "http://icepy.me", body)
if err != nil {
fmt.Println("Fatal error ", err.Error())
}
reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(reqest)
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Fatal error ", err.Error())
}
fmt.Println(string(content))
再来看一个文件上传的例子,不过我个人更喜欢直接传二进制数据,这个比较简单,可以直接[]byte,稍微复杂一些的就是multipart的例子。
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
return nil, err
}
_, err = io.Copy(part, file)
for key, val := range params {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
return nil, err
}
request, err := http.NewRequest("POST", uri, body)
request.Header.Add("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(request)
如果你有细心阅读下,肯定发现了一个使用频率很高的类型url.Values,基本上不管是Get请求的参数还是Post请求的参数,如果你不想自己重复造轮子的话,可以将参数直接.Add在这个对象上,它提供了包括编码的Encode,并且如果你要提交的参数是一个数组的话,也可以很方便的通过循环.Add("arr", arr[i])的方式添加。(额外提一句,因为协议规定的如果是数组,可以如此来描述:“a=1&a=2&a=3”)
上述基本上就是HTTP的Client,接下来要说一说HTTP的Server,基本上也可以预想到,Server端的创建,也很简单。
package main
import (
"net/http"
)
func SayHello(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Hello"))
}
func main() {
http.HandleFunc("/hello", SayHello)
http.ListenAndServe(":8001", nil)
}
首先定义路由规则和对应的Handle,其次是调用ListenAndServer来启动一个8001端口,我们也可以直接使用http.Server。
s := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
不过,对于HTTP Server来说,就要说到如何获取参数的问题了,我们来看一下golang http.request的三个属性Form、PostForm、MultipartForm,简要说明如下,基本上你使用对应的方法,就能获取到相应的参数。