iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Go语言的Handler有什么用
  • 890
分享到

Go语言的Handler有什么用

2023-06-30 04:06:23 890人浏览 泡泡鱼
摘要

这篇文章主要介绍“Go语言的Handler有什么用”,在日常操作中,相信很多人在Go语言的Handler有什么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言的Handler有什么用”的疑惑有所帮助!

这篇文章主要介绍“Go语言的Handler有什么用”,在日常操作中,相信很多人在Go语言的Handler有什么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言的Handler有什么用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Multiplexer根据URL将请求路由给指定的Handler。Handler用于处理请求并给予响应。更严格地说,用来读取请求体、并将请求对应的响应字段(respones header)写入ResponseWriter中,然后返回

Go语言的Handler有什么用

什么是Handler

什么是Handler。它是一个接口,定义在net/Http/server.go中:

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

也就是说,实现了ServerHTTP方法的都是Handler。注意ServerHTTP方法的参数:http.ResponesWriter接口和Request指针。

在Handler的注释中,给出了几点主要的说明:

  • Handler用于响应一个HTTP request

  • 接口方法ServerHTTP应该用来将response header和需要响应的数据写入到ResponseWriter中,然后返回。返回意味着这个请求已经处理结束,不能再使用这个ResponseWriter、不能再从Request.Body中读取数据,不能并发调用已完成的ServerHTTP方法

  • handler应该先读取Request.Body,然后再写ResponseWriter。只要开始向ResponseWriter写数据后,就不能再从Request.Body中读取数据

  • handler只能用来读取request的body,不能修改已取得的Request(因为它的参数Request是指针类型的)

ResponseWriter接口说明

再看看ResponseWriter接口的定义:

// A ResponseWriter interface is used by an HTTP handler to// construct an HTTP response.//// A ResponseWriter may not be used after the Handler.ServeHTTP method// has returned.type ResponseWriter interface {Header() HeaderWrite([]byte) (int, error)WriteHeader(statusCode int)}

注释中已经说明,ResponseWriter接口的作用是用于构造HTTP response。且明确指定了Handler.ServerHTTP方法返回以后就不能再使用ResponseWriter了。

这个接口有3个方法:

  • Header()方法用来构造响应Header,它返回一个Header对象,这个Header对象稍后将被WriterHeader()响应出去。Header类型是一个map类型的结构,字段名为key、字段值为value:

    type Header map[string][]string
  • Write()方法用于向网络连接中写响应数据。

  • WriteHeader()方法将给定的响应状态码和响应Header一起发送出去。

很显然,ResponseWriter的作用是构造响应header,并将响应header和响应数据通过网络链接发送给客户端

再看ListenAndServe()

在启动go http自带的WEB服务时,调用了函数ListenAndServe()。这个函数的定义如下:

func ListenAndServe(addr string, handler Handler) error

该函数有两个参数,第一个参数是自带的web监听地址和端口,第二个参数是Handler,用来处理每个接进来的http request,但一般第二个参数设置为nil,表示调用默认的Multiplexer:DefaultServeMux。这个默认的ServeMux唯一的作用,是将请求根据URL路由给对应的handler进行处理。

var DefaultServeMux = &defaultServeMux

这里有两个问题:

  • (1).第二个参数为什么建议设置为nil

  • (2).设置为nil后,DefaultServeMux是请求的路由器,它为什么可以充当一个handler

先看第二个问题,很简单,因为ServeMux类型定义了ServeHTTP()方法,它实现了Handler接口:

type ServeMux struct {        // Has unexported fields.}func NewServeMux() *ServeMuxfunc (mux *ServeMux) Handle(pattern string, handler Handler)func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)

前面说过,只要实现了ServerHTTP()方法的类型,就是一个Handler。而DefaultServeMux是默认的ServeMux,所以它是一个Handler。

关于第一个问题,看一个示例就知道了。

package mainimport ("fmt""net/http")// MyHandler实现Handler接口type MyHandler struct{}func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!\n")}func main() {handler := MyHandler{}server := http.Server{Addr:    "127.0.0.1:8080",Handler: &handler,      // 以&handler作为第二个参数}server.ListenAndServe()}

上面的示例中定义了一个handler,它实现的ServeHTTP()方法只有一个作用,输出Hello World!。并且将这个handler作为ListenAndServe()的第二个参数。

注意,上面以&handler作为参数而非handler,因为此处MyHandler中实现的ServerHTTP()方法的receiver是指针类型的,所以MyHandler的实例对象也必须是指针类型的,如此才能实现Handler接口。

启动这个web服务后,以不同的URL去访问它,将总是得到完全相同的响应结果:

Go语言的Handler有什么用

很显然,当handler作为ListenAndServe()的第二个参数时,任意请求都会使用这个唯一的handler进行处理

所以,建议将第二个参数设置为nil(或者上面的Serve Struct不指定Handler字段),它表示调用默认的DefaultServeMux作为handler,使得每个访问请求都会调用这个特殊的handler,而这个handler的作用是将请求根据url路由给不同的handler。

另外需要注意的是,http包中提供的Handle()和HandleFunc()函数其实是DefaultServeMux.XXX的封装,所以直接调用http.Handle()和http.HandleFunc()实际上是在调用DefaultServeMux.Handle()和DefaultServeMux.HandleFunc()

func Handle(pattern string, handler Handler) {    DefaultServeMux.Handle(pattern, handler)}func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    DefaultServeMux.HandleFunc(pattern, handler)}

使用DefaultServeMux后的Handler示例

下面是使用了DefaultServeMux的示例。

创建了两个handler,一个handler用于对应/hello,该handler用于输出Hello,另一个handler用于对应world,该handler用于输出World

package mainimport ("fmt""net/http")type HelloHandler struct{}type WorldHandler struct{}func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello\n")}func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "World\n")}func main() {helloHandler := HelloHandler{}worldHandler := WorldHandler{}server := http.Server{Addr:    "127.0.0.1:8080",}http.Handle("/hello",&helloHandler)http.Handle("/world",&worldHandler)server.ListenAndServe()}

下面是访问的结果:

Go语言的Handler有什么用

HandleFunc是什么

除了使用Handle处理http请求,也能使用HandleFunc()处理。

先看一个使用HandleFunc()处理请求的示例,示例的效果和前文是一样的。

package mainimport ("fmt""net/http")func hello(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello\n")}func world(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "World\n")}func main() {server := http.Server{Addr: "127.0.0.1:8080",}http.HandleFunc("/hello", hello)http.HandleFunc("/world", world)server.ListenAndServe()}

下面是访问的结果:

Go语言的Handler有什么用

Go有一个函数HandleFunc(),它表示使用第二个参数的函数作为handler,处理匹配到的url路径请求。

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

不难看出,HandleFunc()使得我们可以直接使用一个函数作为handler,而不需要自定义一个实现Handler接口的类型。正如上面的示例中,我们没有定义Handler类型,也没有去实现ServeHTTP()方法,而是直接定义函数,并将其作为handler。

换句话说,HandleFunc()使得我们可以更简便地为某些url路径注册handler。但是,使用HandleFunc()毕竟是图简便,有时候不得不使用Handle(),比如我们确定要定义一个type。

Handle()、HandleFunc()和Handler、HandlerFunc的关系

说实话,一开始感觉挺乱的。

Handle()和HandleFunc()是函数,用来给url绑定handler。Handler和HandlerFunc类型,用来处理请求

看Handle()、HandleFunc()以及Handler、HandlerFunc的定义就已经很清晰了:

func Handle(pattern string, handler Handler) {}func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {}type Handler interface {ServeHTTP(ResponseWriter, *Request)}type HandlerFunc func(ResponseWriter, *Request)func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)

Handle()和HandleFunc()都是为某个url路径模式绑定一个对应的handler,只不过HandleFunc()是直接使用函数作为handler,而Handle()是使用Handler类型的实例作为handler。

Handler接口的实例都实现了ServeHTTP()方法,都用来处理请求并响应给客户端。

HandlerFunc类型不是接口,但它有一个方法ServeHTTP(),也就是说HandlerFunc其实也是一种Handler

因为HandlerFunc是类型,只要某个函数的签名是func(ResponseWriter, *Request),它就是HandlerFunc类型的一个实例。另一方面,这个类型的实例(可能是参数、可能是返回值类型)可以和某个签名为func(ResponseWriter, *Request)的函数进行互相赋值。这个过程可能很隐式,但确实经常出现相关的用法。

例如:

// 一个函数类型的handlerfunc myhf(ResponseWriter, *Request){}// 以HandlerFunc类型作为参数类型func a(hf HandlerFunc){}// 所以,可以将myhf作为a()的参数a(myhf)

实际上,可以使用HandlerFunc()进行转换。例如有一个函数world(),它的参数是合理的,使用HandlerFunc(world)表示将其转换为一个Handler。这个转换、适应在后面会经常用到。

例如:

// 两个函数func hello(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello\n")}func world(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "World\n")}func main() {server := http.Server{Addr: "127.0.0.1:8080",}    // 第一个使用HandleFunc()为路径注册hello()函数handler    // 第二个使用Handle()为路径注册转换后的handlerhttp.HandleFunc("/hello", hello)http.Handle("/world", http.HandlerFunc(world))server.ListenAndServe()}

上面的示例中,Handle()函数的第二个参数要求的是Handler类型,使用http.HandlerFunc(world)就将函数world()转换成了Handler类型的一个实例。

链式handler

handler是用来处理http请求的,处理过程可能会很简单,也可能会很复杂。复杂的情况下,可能无法使用一个单独的handler来完成工作,毕竟handler只是一个函数。尽管我们可以直接在这个函数中调用其它函数。

很经常地,可能handler中需要嵌套其它handler,甚至多层嵌套,这就是链式handler。

由于Handle()或HandleFunc()注册的时候需要指定参数类型,所以handler嵌套的时候,也要关注handler的参数类型以及返回类型。看下面示例就会明白参数类型和返回类型是怎么要求的。

HandleFunc()的嵌套示例

代码如下:

package mainimport ("fmt""net/http")func hello(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!\n")}func log(hf http.HandlerFunc) http.HandlerFunc {count := 0return func(w http.ResponseWriter, r *http.Request) {count++fmt.Printf("Handler Function called %d times\n", count)hf(w, r)}}func main() {server := http.Server{Addr: "127.0.0.1:8080",}http.HandleFunc("/hello", log(hello))server.ListenAndServe()}

多次访问http://127.0.0.1:8080/hello,将在浏览器中输出"Hello World!",但同时会在运行这个go程序的终端上多次输出以下内容:

$ go run test.goHandler Function called 1 timesHandler Function called 2 timesHandler Function called 3 timesHandler Function called 4 timesHandler Function called 5 times

上面的示例中,主要看下面两段代码:

func hello(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!\n")}func log(hf http.HandlerFunc) http.HandlerFunc {count := 0return func(w http.ResponseWriter, r *http.Request) {count++fmt.Printf("Handler Function called %d times\n", count)hf(w, r)}}

hello()是一个普通的HandlerFunc类型函数,因为它的签名符合HandlerFunc类型,所以它是HandlerFunc类型的一个实例。而log()函数正是以HandlerFunc类型作为参数的,所以前面的示例代码中,将hello函数作为了log函数的参数:

http.HandleFunc("/hello", log(hello))

HandleFunc()的第二个参数要求是HandlerFunc类型的,所以log()的返回值是HandlerFunc类型。在log()中,使用匿名函数作为它的返回值,这里的这个匿名函数是一个闭包(因为引用了外层函数的变量hf和count)。这个匿名函数最后调用hf(w,r),由于hf是HandlerFunc类型的一个实例,所以可以如此调用。

上面体现了HandlerFunc嵌套时候关于参数以及返回值的一些细节。

上面的示例中还有一个细节需要引起注意:为什么每次访问时,上面的count都会记住之前的值并自增,而不是重置为0后自增。

之所以有这个疑问,可能是认为每次访问时,请求处理完成后handler就退出了,闭包虽然会记住外层函数的自由变量count,但也会因为处理完成后退出,导致每次访问都重置为0后自增。但实际上,handler是注册在给定路径上的,只要web服务没有退出,这个handler就一直不会退出,不会因为每次访问都重新注册handler。所以,闭包handler一直引用着hf和count这两个自由变量。

HandlerFunc嵌套Handler

将上面的HandlerFunc嵌套HandlerFunc修改一下,变成Handler嵌套HandlerFunc。

package mainimport ("fmt""net/http")type MyHandler struct{}func (wh *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!\n")}func log(h http.Handler) http.Handler {count := 0f := func(w http.ResponseWriter, r *http.Request) {count++fmt.Printf("Handler Function called %d times\n", count)h.ServeHTTP(w, r)}return http.HandlerFunc(f)}func main() {myHandler := MyHandler{}server := http.Server{Addr: "127.0.0.1:8080",}http.Handle("/hello", log(&myHandler))server.ListenAndServe()}

逻辑也很简单,无非是将HandlerFunc转换成Handler。

思考一下,Handler是否可以嵌套Handler,或者Handler嵌套HandlerFunc。可以,但是很不方便,因为ServeHTTP()方法限制了没法调用其它的Handler,除非定义的某个Handler是嵌套在某个Handler类型中的类型。

到此,关于“Go语言的Handler有什么用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Go语言的Handler有什么用

本文链接: https://www.lsjlt.com/news/327415.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go语言的Handler有什么用
    这篇文章主要介绍“Go语言的Handler有什么用”,在日常操作中,相信很多人在Go语言的Handler有什么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言的Handler有什么用”的疑惑有所帮助!...
    99+
    2023-06-30
  • Go语言Handler详细说明
    Multiplexer根据URL将请求路由给指定的Handler。Handler用于处理请求并给予响应。更严格地说,用来读取请求体、并将请求对应的响应字段(respones head...
    99+
    2024-04-02
  • go语言有什么作用
    go语言作用有:1、构建高性能的网络服务器,go语言能够处理大量的并发连接,实现高效的网络通信;2、在分布式系统中具有重要的作用,Go语言的并发模型非常适合处理分布式系统的编程;3、广泛用于云计算平台的开发,Go语言的高性能和低内存消耗非常...
    99+
    2023-07-10
  • go语言的复数有什么作用
    这篇“go语言的复数有什么作用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“go语言的复数有什么作用”文章吧。在go语言中,...
    99+
    2023-07-04
  • go语言的init()方法有什么用
    在go语言中,init()方法用于包的初始化;初始化每个包后,会自动执行init()函数,并且执行优先级高于主函数的执行优先级。init()方法通常用于:1、变量初始化;2、检查/修复状态;3、注册器;4、运行计算。init()函数在程序运...
    99+
    2023-05-14
    init() go语言 Golang
  • go语言有什么好的ide
    用于go语言的ide有:1、Goland,旨在为Go开发者提供的一个符合人体工程学的商业IDE;2、LiteIDE,一款专门针对Go开发的集成开发环境;3、VSCode,一个跨平台开源代码编辑器;4、Sublime Text,一个跨平台的文...
    99+
    2023-05-14
    go语言 Golang
  • Go语言的接口有什么作用
    本篇内容主要讲解“Go语言的接口有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Go语言的接口有什么作用”吧!Go语言-接口在Go语言中,一个接口类型总...
    99+
    2024-04-02
  • go语言的特点有什么
    Go语言具有”简洁易读“、”并发编程“、”高性能“、”内存安全“、”跨平台支持“、”丰富的标准库“和”静态类型“七个特点:1、Go语言的语法简洁明了,去除了一些冗余和复杂的语法元素,代码相对于其他语言来说更加清晰易读;2、Go语言原生支持轻...
    99+
    2023-12-12
    go语言特点 go语言
  • go语言有什么考试
    go语言有Go语言基础知识考试、Go语言高级知识考试、Go语言框架和库考试、Go语言性能优化考试和一些软件工程机构和科技公司会根据自己的需求设计和实施定制的Go语言考试。1、Go语言基础知识考试,目的是验证考生对Go语言的语法、数据类型、变...
    99+
    2023-08-03
  • go语言有什么好处
    go语言的好处:1、可直接编译成机器码,不依赖其他库;2、静态类型语言,但是有动态语言的感觉,写起来的效率很高;3、语言层面支持并发;4、内置runtime,支持垃圾回收;5、简单易学;6、内置了大量的库,特别是网络库非常强大;7、内置强大...
    99+
    2023-05-14
    go语言
  • go语言有什么特点
    go语言的特点:1、简洁、易读和易写;2、静态类型和编译型;3、高效的并发处理;4、丰富的标准库;5、跨平台和可移植性;6、强大的性能;7、原生支持多范式编程;8、静态类型检查和强类型;9、丰富的第三方库和工具。详细介绍:1、简洁、易读和易...
    99+
    2023-12-11
    go语言
  • go语言的数据类型有什么用
    这篇文章主要讲解了“go语言的数据类型有什么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“go语言的数据类型有什么用”吧!go语言是谷歌2009发布的开源编程语言。Go语言最初由Googl...
    99+
    2023-07-04
  • Go语言error类型有什么作用
    本篇内容主要讲解“Go语言error类型有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Go语言error类型有什么作用”吧!在Go语言,error是一个接口类型。error接口类型是作...
    99+
    2023-07-05
  • Android 中Handler有什么用
    Android 中Handler有什么用,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Android Handler的详解Handler我们常常用于通知主线程做...
    99+
    2023-05-30
    android handler
  • go语言和其他语言有什么不同
    go语言和其他语言的不同之处有:1、Go语言的语法对比其他语言更加直观,减少了开发和维护的时间和精力;2、与其他语言需要不同机制实现并发不同,Go语言通过协程和通道提供了轻量级的并发编程方式;3、与其他语言需要手动管理内存相比,Go语言可以...
    99+
    2023-07-10
  • 有人称Go语言为什么?
    有人称Go语言为什么? 近年来,Go语言作为一种新兴的编程语言备受关注,越来越多的软件开发者选择使用Go语言来开发应用程序。那么,为什么有人称Go语言为“未来之语言”?本文将探讨Go语...
    99+
    2024-04-02
  • go语言有什么新特性
    Go语言的新特性主要集中在以下几个方面:1. 模块化支持:Go 1.11引入了Go模块的概念,可以更方便地管理和复用代码。通过go....
    99+
    2023-10-12
    Go语言
  • Go语言的起源是什么语言?
    Go语言的起源是来自Google开发的一种编程语言,它的设计初衷是为了解决一些在现有语言中存在的问题。Go语言是一种静态类型的编程语言,于2007年开始研发,2009年首次正式发布。G...
    99+
    2024-04-02
  • go语言的底层是什么语言
    go语言的底层是C语言,Go语言是由C和C++开发者创建的,因此它的底层实现也是用C语言编写的,Go语言底层使用了很多C语言的特性和实现方式,如内存管理、指针、函数调用等,这使得Go语言可以直接调用C语言的库函数,也方便了Go语言与其他编程...
    99+
    2023-07-10
  • python和go语言的区别有什么
    本篇文章为大家展示了python和go语言的区别有什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。go语言Go(又称 Golang)是 Google 的 Robert Griesemer,Rob ...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作