Go之Http包的服务端介绍

news/2024/7/19 13:29:45 标签: java, python, go, js, http
js_content">

对于go的net/http包,主要分为两个部分,一部分是针对客户端的,一部分是针对服务端的,本篇文章主要介绍服务端这部分内容。

一、总体介绍

一个http消息的流程如下所示,其中红框部分是server部分的内容,主要包括两部分内容:ServerMux 和 Handler。

https://img-blog.csdnimg.cn/img_convert/fae8ac42bfb72e0943160d2a8af02032.png" />

ServerMux 本质上是一个 HTTP 请求路由器(也叫多路复用器Multiplexor)。它把收到的请求与一组预先定义的 URL 路径列表做对比,然后在匹配到路径的时候调用关联的处理器(Handler)。

处理器(Handler)负责输出HTTP响应的头和正文,任何满足了http.Handler接口的对象都可作为一个处理器。

二、ServerMux介绍

ServerMux 本质上是一个 HTTP 请求路由器(或者叫多路复用器,Multiplexor)。它把收到的请求与一组预先定义的 URL 路径列表做对比,然后在匹配到路径的时候调用关联的处理器(Handler)。

1.Go中既可以使用内置的mutilplexer 也就是DefautServeMux,也可以自定义。Multiplexer路由的目的就是为了找到处理器函数(handler),后者将对request进行处理,同时构建response。

源码如下所示:

type ServeMux struct {
    mu    sync.RWMutex  //锁,因为请求是并发处理的,所以这里需要锁机制
    m     map[string]muxEntry //路由规则的map,一个string对应一个muxEntry
    es    []muxEntry 
    hosts bool       
}


type muxEntry struct {
    h       Handler    //string对应的处理器
    pattern string     //匹配的字符串
}

默认的DefaultServerMux是根据请求的URL与存储的map做匹配,匹配到了就返回对应的handler,然后调用该handler的ServeHTTP方法来处理请求,源码如下:

go">func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
    if r.RequestURI == "*" {
        if r.ProtoAtLeast(1, 1) {
            w.Header().Set("Connection", "close")
        }
        w.WriteHeader(StatusBadRequest)
        return
    }
    h, _ := mux.Handler(r)
    h.ServeHTTP(w, r)
}


func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {


    if r.Method == "CONNECT" {
        if u, ok := mux.redirectToPathSlash(r.URL.Host, r.URL.Path, r.URL); ok {
            return RedirectHandler(u.String(), StatusMovedPermanently), u.Path
        }


        return mux.handler(r.Host, r.URL.Path)
    }


    host := stripHostPort(r.Host)
    path := cleanPath(r.URL.Path)


    if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok {
        return RedirectHandler(u.String(), StatusMovedPermanently), u.Path
    }


    if path != r.URL.Path {
        _, pattern = mux.handler(host, path)
        url := *r.URL
        url.Path = path
        return RedirectHandler(url.String(), StatusMovedPermanently), pattern
    }


    return mux.handler(host, r.URL.Path)
}


func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
    mux.mu.RLock()
    defer mux.mu.RUnlock()


    if mux.hosts {
        h, pattern = mux.match(host + path)
    }
    if h == nil {
        h, pattern = mux.match(path)
    }
    if h == nil {
        h, pattern = NotFoundHandler(), ""
    }
    return
}

2.当然ServerMux也可以自己实现,例子如下:

go">package main
import (
    "fmt"
    "net/http"
)
// 自定义一个多路复用器的结构
type MyTestMux struct{}


// 实现ServeHTTP方法
func (m MyTestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 判断URL并转到对应的handler处理
    if r.URL.Path == "/test" {
        TestHandler(w, r)
        return
    }


    http.NotFound(w, r)
    return
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "This is Test page")
}


func main() {
    // 实例化一个自定义的路由器
    mux := MyTestMux{}
    err := http.ListenAndServe(":9000", mux) // 这里指定使用自定义的mux
    if err != nil {
        fmt.Println(err)
    }
}

三、处理器Handler

处理器(Handler)负责输出HTTP响应的头和正文,任何满足了http.Handler接口的对象都可作为一个处理器。通俗的说,对象只要有个如下签名的ServeHTTP方法即可,如下所示:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)   //路由具体实现
}

处理器的使用往往采用下面两种方式:

1.自定义处理器,例子如下:

go">package main
import (
  "log"
  "net/http"
)


type TestHandler struct {
  Data string // 这里可以添加自己需要的数据内容
}
// 实现ServeHTTP函数
func (th *TestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("The time is: " + th.Data))
}


func main() {
  mux := http.NewServeMux() // 新建一个自定义的mux
  th := &TesteHandler{Data: "test"}
  mux.Handle("/test", th) // 将handle添加一个th


  log.Println("Listening...")
  http.ListenAndServe(":9000", mux) // 关联成自定义的mux
}

2.通过http.HandlerFunc 将函数转换成处理器

任何有 func(http.ResponseWriter, *http.Request) 签名的函数都能转化为一个 HandlerFunc 类型。因为 HandlerFunc 对象内置了 ServeHTTP 方法,后者可以聪明又方便的调用我们最初提供的函数内容。例子如下所示:

go">package main
import (
  "log"
  "net/http"
  "time"
)
func TestHandler(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("The Test is: " + "test"))
}


func main() {
  mux := http.NewServeMux()
  // 将TestHandler转换成handler
  th := http.HandlerFunc(TestHandler)
  mux.Handle("/test", th)//添加到到handle中


  log.Println("Listening...")
  http.ListenAndServe(":9000", mux)//关联成自定义的mux
}

四、服务端处理http请求的流程是什么样子的?

我们通过使用默认的DefautServeMux为例,来讲解下http服务端的处理流程,这里分析的是下面这种最常用的代码实现方式:

func TestHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Request.URL.Path: %s!", r.URL.Path[1:])
}


func main() {
    http.HandleFunc("/", TestHandler)
    log.Fatal(http.ListenAndServe(":  9000", nil))
}

执行流程如下所示:

https://img-blog.csdnimg.cn/img_convert/a4e147c59e80ac39021502c278bda149.png" />

参考文档:

https://draveness.me/golang/docs/part4-advanced/ch09-stdlib/golang-net-http/#%E6%B3%A8%E5%86%8C%E5%A4%84%E7%90%86%E5%99%A8

https://www.jianshu.com/p/4e8cdf3b2f88

https://www.jianshu.com/p/16210100d43d

https://www.jianshu.com/p/be3d9cdc680b

https://studygolang.com/articles/9467

https://learnku.com/docs/build-web-application-with-golang/034-gos-http-package-detailed-solution/3171


http://www.niftyadmin.cn/n/872989.html

相关文章

开发完成后总结心得(团队会议稿)

开发完成后总结心得(团队会议稿) 转载自: http://www.cnblogs.com/cj723/archive/2006/09/08/498996.html 前阶段开发中存在的问题, 及改进建议(下面提到的问题在任何软件公司都会碰到,所以出现也是很正常&#xff…

kali linux tcl安装教程,install.sh

#!/bin/bash# 获取linux发行版名称function get_linux_distro(){if grep -Eq "Ubuntu" /etc/*-release; thenecho "Ubuntu"elif grep -Eq "Deepin" /etc/*-release; thenecho "Deepin"elif grep -Eq "LinuxMint" /etc/*-rel…

Redis集群的重定向

本文主要来介绍redis集群的重定向问题。一、重定向产生的原因对于Redis的集群来说,因为集群节点不能代理(proxy)命令请求, 所以客户端应该在节点返回 -MOVED 或者 -ASK 转向(redirection)错误时&#xff0c…

Service Mesh到底解决什么问题

写在前面的话:最近在学习Service Mesh,也系统看了下它的原理以及演进过程,算是对Service Mesh 有了一个认识,便尝试着整理下Service Mesh一些文章,而这篇文章也是本系列的第一篇文章。本篇文章主要的目的是想讲清楚下面…

linux网络验证失败,curl:(35)gnutls_handshake()失败:公钥签名验证失败

我有一个问题,当我做curl请求或git push时,给我看curl: (35) gnutls_handshake() failed: Public key signature verification has failed.卷曲 – 翻译curl 7.50.1 (x86_64-pc-Linux-gnu) libcurl/7.50.1 GnuTLS/3.5.3 zlib/1.2.8 libidn/1.33 libssh2/1.7.0 nghttp2/1.14.0 l…

linux嵌入式swift,ios – 存档时Swift嵌入式框架构建失败

我在项目中添加了一个swift框架作为子项目.当我在模拟器和设备上运行时,它工作正常.但是,当我尝试归档主要产品时,它失败并出现错误:“/Users/mac/Library/Developer/Xcode/DerivedData/ProductName-bhtbyknuwzpjjwaadaqiytxtzypo/Build/Intermediates/ArchiveInter…

Service Mesh之Istio

本篇文章是本人学习Service Mesh的第二章,主要用来介绍当前最流行的一个Service Mesh落地产品Istio。本篇文章的目的主要希望从大的层面弄清楚下面几点:1. Isti是什么? 2. Istio长什么样子? 3. Istio 为什么这么设计?问…

Service Mesh之Envoy

写在前面的话: 本篇文章,主要希望讲清楚,下面几个问题: 1.Envoy是什么,长什么样子? 2.Envoy解决了什么问题? 3.使用它的好处在哪里?简介: Envoy是一款由 Lyft 开源的高性…