Golang 语言怎么使用 net/http 标准库开发 http 应用?

简介: Golang 语言怎么使用 net/http 标准库开发 http 应用?

介绍

在 Golang 语言中,可以使用 net/http 实现 http server,可以通过调用 ListenAndServe 函数,传入给定参数,地址和处理器 (handler)。处理器参数为 nil 时,默认使用 DefaultServeMux

也可以使用 net/http 标准库实现 http client。可以通过调用 GetHeadPost,和 PostForm 函数发送 http(或 https) 请求。需要注意的是,客户端完成请求后,必须关闭响应主体。

Server

使用 net/http 标准库实现 http server,通常有两种方式,分别是使用处理器和使用处理器函数。

处理器 Handler

其中,处理器方式包含单个处理器和多个处理器。

单个处理器,示例代码:

func main () {
 hello := Hello{name: "frank"}
 httpServer := http.Server{Addr: ":8080", Handler: &hello}
 httpServer.ListenAndServe()
}
type Hello struct {
 name string
}
func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "hello " + h.name)
}

阅读上面这段代码,我们发现定义一个结构体类型的变量,通过实现 ServeHTTP(ResponseWriter, *Request) 方法,创建 Handler,并将其赋值给 http.Server 的 Handler 字段。

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

阅读源码,可以发现 Handler 是包含一个 ServeHTTP(ResponseWriter, *Request) 方法的接口。

使用单个处理器的方式,方便传参,但是,不可以匹配多个路由,所以如果需要匹配多个路由,我们可以使用多个处理器的方式。

多个处理器,示例代码:

func main () {
 httpServer := http.Server{
  Addr:              ":8080",
 }
 http.Handle("/hello", Hello{})
 http.Handle("/world", World{})
 httpServer.ListenAndServe()
}
type Hello struct {}
type World struct {}
func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "hello")
}
func (w1 World) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "world")
}

阅读上面这段代码,可以发现,我们创建了多个处理器,然后调用 http.Handle 函数,将处理器注册到 DefaultServeMux,多路复用器将路由请求转发给该路由的 ServerHTTP 方法处理。

使用多个处理器的方式,可以一个处理器匹配一个路由,通过创建多个处理器,可以匹配多个路由。

处理器函数

处理器方式,一个路由对应一个处理器(handler),当我们有多个路由时,需要创建多个处理器,使用上有些繁琐。因此,net/http 标准库提供了一个函数 HandleFunc,它可以将传参的路由和 handler func 注册到 DefaultServeMux

handler func 也实现了 Handler 结构体的 ServeHTTP(ResponseWriter, *Request) 方法。

处理器函数(handler func),示例代码:

func main () {
 http.HandleFunc("/hello", hello)
 http.HandleFunc("/world", world)
 err := http.ListenAndServe(":8080", nil)
 if err != nil {
  log.Fatal(err)
 }
}
func hello(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "hello")
}
func world(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "world")
}

阅读上面这段代码,我们发现使用处理器函数的方式,相比使用处理器的方式,代码量减少了。但是,传参就变得不优雅了,我们在使用时可以根据场景择优选择。

聪明的读者朋友们可能发现,以上示例中使用的是 DefaultServeMux,为什么没有使用函数 http.NewServeMux 创建一个新的多路复用器?

因为 net/http 标准库会默认创建 DefaultServeMux。函数 http.Handlehttp.HandleFunc 将处理器注册到 DefaultServeMux,在 ListenAndServe 未接收到 handler 参数时,默认使用 DefaultServeMux

源码如下:

func NewServeMux() *ServeMux { return new(ServeMux) }
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
 DefaultServeMux.HandleFunc(pattern, handler)
}

我们也可以创建一个新的多路复用器,管理路由请求,包含处理器模式和处理器函数模式。

处理器模式,示例代码:

func main () {
 serveMux := http.NewServeMux()
 hello := Hello{}
 serveMux.Handle("/hello", hello)
 http.ListenAndServe(":8080", serveMux)
}
type Hello struct {}
func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "hello")
}

阅读上面这段代码,使用创建的多路复用器,调用多路复用器的 Handle 方法注册处理器(Handler)。

处理器函数模式,示例代码:

func main () {
 serveMux := http.NewServeMux()
 hello := http.HandlerFunc(Hello)
 serveMux.Handle("/hello", hello)
 http.ListenAndServe(":8080", serveMux)
}
func Hello (w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "hello")
}

阅读上面这段代码,使用函数 http.HandlerFunc 将传入函数类型的参数转义为 HandlerFunc。

03

Client

使用 net/http 标准库实现 http client。可以通过调用 GetHeadPost,和 PostForm 函数发送 http(或 https) 请求。需要注意的是,客户端完成请求后,必须关闭响应主体。

示例代码:

func main () {
 http.HandleFunc("/client", client)
 err := http.ListenAndServe(":8080", nil)
 if err != nil {
  log.Fatal(err)
 }
}
func client(w http.ResponseWriter, r *http.Request) {
 resp, err := http.Get("http://127.0.0.1:8080/hello")
 if err != nil {
  log.Fatal(err)
 }
 data, err := io.ReadAll(resp.Body)
 if err != nil {
  log.Fatal(err)
 }
 defer resp.Body.Close()
 fmt.Fprintln(w, string(data))
}

04

Request Param

关于接收请求参数,http.Request 也提供了一些函数和方法,限于篇幅,本文仅提供一个示例,对此不准备过多介绍。

func main () {
 http.HandleFunc("/param1", param1)
 http.HandleFunc("/param2", param2)
 err := http.ListenAndServe(":8080", nil)
 if err != nil {
  log.Fatal(err)
 }
}
func param1(w http.ResponseWriter, r *http.Request) {
 r.ParseForm()
 fmt.Fprintln(w, r.Form["user"][0])
}
func param2(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, r.FormValue("user"), r.FormValue("age"))
}

阅读上面这段代码,我们定义了两个接收请求参数的函数,分别通过 r.ParseFormr.FormValue 方法获取请求参数,其中 r.ParseFome 方法是将参数解析到 r.Form 中,r.FormValue 方法直接返回一个字符串类型的给定参数 key 的第一个值。关于更多使用方式,请阅读官方文档。

05

Response Result

关于响应结果,http.ResponseWriter 接口也提供了三个方法:

type ResponseWriter interface {
 Header() Header
 Write([]byte) (int, error)
 WriteHeader(statusCode int)
}

限于篇幅,在此也不做过多介绍,仅提供一个示例。关于更多使用方式,请阅读官方文档。

func main () {
 http.HandleFunc("/json", jsonRes)
 err := http.ListenAndServe(":8080", nil)
 if err != nil {
  log.Fatal(err)
 }
}
func jsonRes(w http.ResponseWriter, r *http.Request) {
 w.Header().Set("Content-Type", "application/json")
 ageStr := r.FormValue("age")
 ageInt, err := strconv.Atoi(ageStr)
 if err != nil {
  log.Fatal(err)
 }
 age := uint8(ageInt)
 username := r.FormValue("user")
 jsonData, err := json.Marshal(struct {
  Username string
  Age uint8
 }{username, age})
 if err != nil {
  log.Fatal(err)
 }
 fmt.Fprintln(w, string(jsonData))
}

06

总结

本文我们主要介绍使用 net/http 标准库实现 http server 和 http client 的使用方式。并简单列举了请求参数和响应结果的使用示例。关于 Cookie 的操作,在之前的公众号文章中介绍过,本文也没有重复赘述。

重点需要掌握的是处理器和多路复用器,包括处理器和处理器函数,以及新建多路复用器和默认多路复用器。此外,net/http 标准库还有几个内置函数,可以作为处理器,比如函数 NotFoundHandlerRedirectHandler 等。

阅读完本文,读者朋友们应该已经了解 Golang 语言怎么使用 net/http 标准库开发 http 应用。

推荐阅读:

参考资料:

https://golang.org/pkg/net/http/ 

目录
相关文章
|
8月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
392 2
|
中间件 Go
Golang | Gin:net/http与Gin启动web服务的简单比较
总的来说,`net/http`和 `Gin`都是优秀的库,它们各有优缺点。你应该根据你的需求和经验来选择最适合你的工具。希望这个比较可以帮助你做出决策。
672 35
|
Go
在golang中发起http请求以获取访问域名的ip地址实例(使用net, httptrace库)
这只是追踪我们的行程的简单方法,不过希望你跟着探险家的脚步,即使是在互联网的隧道中,也可以找到你想去的地方。接下来就是你的探险之旅了,祝你好运!
636 26
|
JSON API Go
Golang工程组件:自定义HTTP规则的grpc-gateway选项
总的来说,grpc-gateway提供了一种简单有效的方式来为你的gRPC服务提供RESTful风格的API。通过自定义HTTP规则,你可以灵活地定义你的API的行为,以满足你的应用的需求。
364 27
|
缓存 Go
如何解决Golang开发中校验和不匹配问题
以上就是解决Golang开发中校验和不匹配问题的一些方法。这就像小刺猬解决他的“果酱瓶”问题一样,清理错误、替换新的、打破旧的,希望对你有所帮助!
228 5
|
Go 开发者
go-carbon v2.6.0 重大版本更新,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持
328 3
|
人工智能 芯片
D1net阅闻|OpenAI员工疯狂暗示,内部已成功开发ASI?被曝训出GPT-5但雪藏
D1net阅闻|OpenAI员工疯狂暗示,内部已成功开发ASI?被曝训出GPT-5但雪藏
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
583 0
|
Linux API C#
基于 .NET 开发的多功能流媒体管理控制平台
基于 .NET 开发的多功能流媒体管理控制平台
316 9
|
网络协议 测试技术 Linux
Golang 实现轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库
gev 是一个基于 epoll 和 kqueue 实现的高性能事件循环库,适用于 Linux 和 macOS(Windows 暂不支持)。它支持多核多线程、动态扩容的 Ring Buffer 读写缓冲区、异步读写和 SO_REUSEPORT 端口重用。gev 使用少量 goroutine,监听连接并处理读写事件。性能测试显示其在不同配置下表现优异。安装命令:`go get -u github.com/Allenxuxu/gev`。
396 0