GO 内置的Http

简介(≈废话很多人是这么认为的)

在当今数字化的时代,Web应用程序的开发和网络通信变得愈发重要。为了构建强大的Web服务和客户端,开发者需要熟悉各种网络协议和工具。而在Go语言中,内置的net/http包提供了一种出色的方式来处理HTTP请求和响应,不仅功能强大,而且易于使用。本文将带你深入了解Go语言内置的net/http包,揭示其强大的功能和用法。

Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现。
net/http介绍 Go语言内置的net/http包提供了HTTP客户端和服务端的实现。

HTTP协议

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。

HTTP客户端

基本的HTTP/HTTPS请求 Get、Head、Post和PostForm函数发出HTTP/HTTPS请求。

go 复制代码
resp, err := http.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
...
resp, err := http.PostForm("http://example.com/form",
  url.Values{"key": {"Value"}, "id": {"123"}})

程序在使用完response后必须关闭回复的主体。

go 复制代码
resp, err := http.Get("http://example.com/")
if err != nil {
  // handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
// ...

GET请求示例

使用net/http包编写一个简单的发送HTTP请求的Client端,代码如下:

go 复制代码
package main
​
import (
  "fmt"
  "io/ioutil"
  "net/http"
)
​
func main() {
  resp, err := http.Get("https://www.liwenzhou.com/")
  if err != nil {
    fmt.Printf("get failed, err:%v\n", err)
    return
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Printf("read from resp.Body failed, err:%v\n", err)
    return
  }
  fmt.Print(string(body))
}

将上面的代码保存之后编译成可执行文件,执行之后就能在终端打印liwenzhou.com网站首页的内容了,我们的浏览器其实就是一个发送和接收HTTP协议数据的客户端,我们平时通过浏览器访问网页其实就是从网站的服务器接收HTTP数据,然后浏览器会按照HTML、CSS等规则将网页渲染展示出来。

带参数的GET请求示例

关于GET请求的参数需要使用Go语言内置的net/url这个标准库来处理。

go 复制代码
func main() {
  apiUrl := "http://127.0.0.1:9090/get"
  // URL param
  data := url.Values{}
  data.Set("name", "小王子")
  data.Set("age", "18")
  u, err := url.ParseRequestURI(apiUrl)
  if err != nil {
    fmt.Printf("parse url requestUrl failed, err:%v\n", err)
  }
  u.RawQuery = data.Encode() // URL encode
  fmt.Println(u.String())
  resp, err := http.Get(u.String())
  if err != nil {
    fmt.Printf("post failed, err:%v\n", err)
    return
  }
  defer resp.Body.Close()
  b, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Printf("get resp failed, err:%v\n", err)
    return
  }
  fmt.Println(string(b))
}

对应的Server端HandlerFunc如下:

scss 复制代码
func getHandler(w http.ResponseWriter, r *http.Request) {
  defer r.Body.Close()
  data := r.URL.Query()
  fmt.Println(data.Get("name"))
  fmt.Println(data.Get("age"))
  answer := `{"status": "ok"}`
  w.Write([]byte(answer))
}

Post请求示例

上面演示了使用net/http包发送GET请求的示例,发送POST请求的示例代码如下:

go 复制代码
package main
​
import (
  "fmt"
  "io/ioutil"
  "net/http"
  "strings"
)
​
// net/http post demo
​
func main() {
  url := "http://127.0.0.1:9090/post"
  // 表单数据
  //contentType := "application/x-www-form-urlencoded"
  //data := "name=小王子&age=18"
  // json
  contentType := "application/json"
  data := `{"name":"小王子","age":18}`
  resp, err := http.Post(url, contentType, strings.NewReader(data))
  if err != nil {
    fmt.Printf("post failed, err:%v\n", err)
    return
  }
  defer resp.Body.Close()
  b, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Printf("get resp failed, err:%v\n", err)
    return
  }
  fmt.Println(string(b))
}

对应的Server端HandlerFunc如下:

go 复制代码
func postHandler(w http.ResponseWriter, r *http.Request) {
  defer r.Body.Close()
  // 1. 请求类型是application/x-www-form-urlencoded时解析form数据
  r.ParseForm()
  fmt.Println(r.PostForm) // 打印form数据
  fmt.Println(r.PostForm.Get("name"), r.PostForm.Get("age"))
  // 2. 请求类型是application/json时从r.Body读取数据
  b, err := ioutil.ReadAll(r.Body)
  if err != nil {
    fmt.Printf("read request.Body failed, err:%v\n", err)
    return
  }
  fmt.Println(string(b))
  answer := `{"status": "ok"}`
  w.Write([]byte(answer))
}

自定义Client

要管理HTTP客户端的头域、重定向策略和其他设置,创建一个Client:

go 复制代码
client := &http.Client{
  CheckRedirect: redirectPolicyFunc,
}
resp, err := client.Get("http://example.com")
// ...
req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
// ...

自定义Transport

要管理代理、TLS配置、keep-alive、压缩和其他设置,创建一个Transport:

css 复制代码
tr := &http.Transport{
  TLSClientConfig:    &tls.Config{RootCAs: pool},
  DisableCompression: true,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://example.com")

Client和Transport类型都可以安全的被多个goroutine同时使用。出于效率考虑,应该一次建立、尽量重用。

服务端

默认的Server

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

Handle和HandleFunc函数可以向DefaultServeMux添加处理器。

go 复制代码
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Fatal(http.ListenAndServe(":8080", nil))

默认的Server示例

使用Go语言中的net/http包来编写一个简单的接收HTTP请求的Server端示例,net/http包是对net包的进一步封装,专门用来处理HTTP协议的数据。具体的代码如下:

go 复制代码
// http server
​
func sayHello(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Hello 沙河!")
}
​
func main() {
  http.HandleFunc("/", sayHello)
  err := http.ListenAndServe(":9090", nil)
  if err != nil {
    fmt.Printf("http server failed, err:%v\n", err)
    return
  }
}

将上面的代码编译之后执行,打开你电脑上的浏览器在地址栏输入127.0.0.1:9090回车,此时就能够看到。hello页面

自定义Server 要管理服务端的行为,可以创建一个自定义的Server:

yaml 复制代码
s := &http.Server{
  Addr:           ":8080",
  Handler:        myHandler,
  ReadTimeout:    10 * time.Second,
  WriteTimeout:   10 * time.Second,
  MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())

总结

在Go语言中,net/http包是构建高性能Web应用程序的强大工具,它提供了丰富的功能和简单的API,使开发者能够轻松创建HTTP客户端和服务端。通过本文的示例和介绍,你已经了解了如何发送GET和POST请求,处理参数,自定义客户端和服务端,以及创建自定义路由处理器。这将为您的Go语言开发工作提供坚实的基础,让您能够构建出色的Web应用程序和服务。继续探索net/http包的强大功能,并在你的下一个项目中充分利用它。

相关推荐
Think Spatial 空间思维23 分钟前
【HTTPS基础概念与原理】对称加密与非对称加密在HTTPS中的协作
网络协议·http·https
喝醉的小喵24 分钟前
【mysql】并发 Insert 的死锁问题 第二弹
数据库·后端·mysql·死锁
kaixin_learn_qt_ing1 小时前
Golang
开发语言·后端·golang
炒空心菜菜2 小时前
MapReduce 实现 WordCount
java·开发语言·ide·后端·spark·eclipse·mapreduce
wowocpp4 小时前
spring boot Controller 和 RestController 的区别
java·spring boot·后端
后青春期的诗go4 小时前
基于Rust语言的Rocket框架和Sqlx库开发WebAPI项目记录(二)
开发语言·后端·rust·rocket框架
freellf4 小时前
go语言学习进阶
后端·学习·golang
全栈派森6 小时前
云存储最佳实践
后端·python·程序人生·flask
CircleMouse6 小时前
基于 RedisTemplate 的分页缓存设计
java·开发语言·后端·spring·缓存
獨枭7 小时前
使用 163 邮箱实现 Spring Boot 邮箱验证码登录
java·spring boot·后端