Golang之http server

基于HTTP构建的网络应用包括两个端,即客户端(Client)和服务端(Server)。两个端的交互行为包括从客户端发出request、服务端接受request进行处理并返回response以及客户端处理response。所以http服务器的工作就在于如何接受来自客户端的request,并向客户端返回respond。
典型的http服务端处理流程:
服务器在接收到请求时,首先会进入路由(router),这是一个Multiplexer,路由的工作在于为这个request找到对应的处理器(handler),处理器对request进行处理,并构建response。GOlang实现的http server同样遵循这样的处理流程

http server实现一

package main

import (
	"fmt"
	"net/http"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "hello world")
}

func main() {
	http.HandleFunc("/", indexHandler)
	http.ListenAndServe(":8000", nil)
}

在这里插入图片描述
运行代码之后,在浏览器中打开localhost:8000就可以看到hello world 。这段代码先利用http.HandleFunc在跟路由/ 上注册了一个indexHandler,然后利用http.ListenAndServe开启监听。当有请求过来时,则根据路由执行对应的handler函数。

http server 实现方式之二

package main

import (
    "fmt"
    "net/http"
)

type indexHandler struct {
    content string
}

func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, ih.content)
}

func main() {
    http.Handle("/", &indexHandler{content: "hello world!"})
    http.ListenAndServe(":8001", nil)
}

在这里插入图片描述
发现并没有进入监听状态,可能是端口被占用了
筛选8001端口的进程 netstat -ano |findstr “8001”
在这里插入图片描述
强制(/F参数)杀死 pid 为 9088 的所有进程包括子进程(/T参数):

taskkill /T /F /PID 592
在这里插入图片描述
再次运行 发现可以了 进入监听状态
在这里插入图片描述
Go实现的http服务步骤,首先注册路由,然后创建服务并开启监听即可。下文我们将从注册路由、开启服务、处理请求这几个步骤了解Golang如何实现http服务

注册路由

http.HandleFunc和http.Handle都是用于注册路由,可以发现两者的区别在于第二个参数,前者是一个具有func(w http.ResponseWriter,r *http.Request)签名的函数,而后者是一个结构体,该结构体实现了func(w http.ResponseWriter ,r **http.Requests)签名的方法。
http.HandleFunc和http.Handle的源码如下:`

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}
//HandleFunc registers the handler function  for  the  given  pattern
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}

可以看到这两个函数 最总都由DefaultServeMux调用Handle方法来完成路由的注册。
这里我们遇到两种类型的对象:ServeMux和Handler

Handler

handler是一个接口:

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

Handler接口种声明了名为ServeHTTP的函数签名,也就是说任何结构只要实现了这个ServeHTTP方法,那么这个结构体就是一个Handler对象,其实go的http服务都是基于Handler进行处理,而Handler对象的ServeHTTP方法也正是用以处理request并构建response的核心逻辑所在。

回到上面的HandlerFunc函数,注意一下这行代码:

mux.Handle(pattern,HandleFunc(handler))

可能有人会误认为HandleFunc是一个函数,包装了传入handler函数,返回了一个Handler对象。然而这里HandlerFunc实际上是将handler函数做了一个类型转换,看下HandlerFunc的定义:

type HandlerFunc  func(ResponseWriter,*Request)
//ServeHTTP  call f(w,r)
func(f HandlerFunc) ServerHTTP(w ResponseWriter,r *Request){
   f(w,r)
}

HandlerFunc是一个类型,只不过表示的是一个具有func(ResponseWriter, *Request)签名的函数类型,并且这种类型实现了ServeHTTP方法(在ServeHTTP方法中又调用了自身),也就是说这个函数其实就是一个Handler类型的对象,利用这种类型转换,我们可以将一个handler函数转换为一个Handler对象,而不需要定义一个结构体,再让这个结构体实现ServeHTTP方法

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生活热爱就好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值