1 GO语言初探web开发与ServeMux与中间件

Posted 行走的皮卡丘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1 GO语言初探web开发与ServeMux与中间件相关的知识,希望对你有一定的参考价值。


1 GO语言初探web开发与ServeMux与中间件

1 Hello World

package main

import(
	"fmt"
	"net/http"
)

func helloworld(w http.ResponseWriter, r *http.Request) 
	fmt.Fprintf(w, "hello world!")


func main() 

	http.HandleFunc("/hello", helloworld)

	server := http.Server
		Addr: ":8081",
	
	server.ListenAndServe()


访问:localhost:8081/hello,页面输出:hello world!
运行代码

访问:localhost:8081/hello,页面输出:hello world!

2 常见功能

2.1 静态文件管理

在helloworld项目的目录中创建文件夹public用于存放html静态文件:

    files := http.FileServer(http.Dir("./public"))
    http.Handle("/static/", http.StripPrefix("/static/", files)) 

注意:

  • 直接使用编辑器运行会造成路径不正确,应该先使用 go build 后,运行二进制文件。推荐使用绝对路径:os.Executable()获取绝对路径
  • 访问类似http://localhost:8080/static/hello.html网址,服务端会替换掉static为public路径

2.2 参数获取

package main

import(
	"fmt"
    "net/http"
)

func helloworld(w http.ResponseWriter, r *http.Request) 

    // 默认不会解析,需要先解析表单
    err := r.ParseForm()
    if err != nil 
        fmt.Println("参数解析出错:", err)
        return
    
	
    fmt.Println("path", r.URL.Path)	    // 输出 /
    fmt.Println(r.Form)                 // 输出 map[id:[4] name:[LYY]]

	fmt.Fprintf(w, "helloworld")


func main() 

    http.HandleFunc("/hello", helloworld)
    
    files := http.FileServer(http.Dir("./public"))
    http.Handle("/static/", http.StripPrefix("/static/", files))

    server := http.Server
		Addr: ":8081",
    
	server.ListenAndServe()


GETPOST方式访问时,参数解析都会得到支持:

  • GET方式访问:访问地址为 localhost:8080/?id=4&name=LYY
  • POST方式访问:在hello.html文件中加入如下ajax访问方式
    <script src="../lib/jquery1.11.3.js"></script>
    <script>
        $.ajax(
            type: "POST",
            url: "/hello",
            data: 
                "id": 4,
                "name": "LYY",
            ,
            success: function (data) 
                console.log("data=",data);
            ,
            error: function(err)
                console.log("err=",err);
            
        )
    </script>

2.3 模板引擎

笔者是坚定的前后端分离主义者,这里只是介绍go默认模板引擎的基本使用。

在Go语言中,使用template包来进行模板处理,使用类似ParseParseFileExecute等方法从文件或者字符串加载模板。

在上述helloworld案例的main函数中添加一个处理函数:

	http.HandleFunc("/testTemplate", testTemplate)

处理函数为:

    // 解析模板文件
    t, _ := template.ParseFiles("./views/test.html")
    // 声明一个字符串切片
    stars := []string"LYY", "CXM", "CWT"
    // 执行模板
    t.Execute(w, stars)

创建一个模板文件views/test.html

<body>
     <!-- 嵌入动作 -->
     range .
     <a href="#">.</a>
    else
     没有遍历到任何内容
    end  
</body>

3 Handler

在golang的web开发中,一个handler响应一个http请求:

type Handler interface
    ServerHTTP(ResponseWriter, *Request)

Handler可以有多种实现方式:

// 实现一:HandlerFunc。
// HandlerFunc是对是用户定义的处理函数的包装,实现了ServeHTTP方法,在方法内执行HandlerFunc对象
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) 
    f(w, r)


// 实现二:ServeMux
// ServeMux是管理http请求pattern和handler的,实现了ServeHTTP方法,在其内根据请求匹配HandlerFunc,并执行其ServeHTTP方法
type ServeMux struct 
    mu    sync.RWMutex
    m     map[string]muxEntry
    es    []muxEntry // slice of entries sorted from longest to shortest.
    hosts bool       // whether any patterns contain hostnames

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) 
    h, _ := mux.Handler(r)
    h.ServeHTTP(w, r) // 调用的是HandlerFunc的ServeHTTP



// 实现三:serverHandler
// serverHandler是对Server的封装,实现了ServeHTTP方法,并在其内执行ServeMux的ServeHTTP方法
type serverHandler struct 
    srv *Server

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) 
    handler := sh.srv.Handler
    if handler == nil 
        handler = DefaultServeMux
    
    ...
    handler.ServeHTTP(rw, req) // 调用的是ServerMux的ServeHTTP


4 ServeMux

ServeMux是一个HTTP请求多路复用器。它根据已注册模式(pattern)列表匹配每个传入请求的URL,并调用与URL最匹配的模式的处理程序(handler)。

按照第一章的方式构建三个服务接口:

    http.HandleFunc("/", mainHandler)
    http.HandleFunc("/hello/", helloHandler)
    http.HandleFunc("/world/", worldHandler)

	server := http.Server
		Addr: ":8081",
    
	server.ListenAndServe()

此时访问:

  • localhost:8081/hello:会响应helloHandler函数
  • localhost:8081/hello/:同样会响应helloHandler函数

实际上,访问localhost:8081/hello时,其实会以301重定向方式自动补齐为:/hello/,然后浏览器自动发起第二次请求。

如果使用ServeMux注册路由:

    mux := http.NewServeMux()
    mux.HandleFunc("/", mainHandler)
    mux.HandleFunc("/hello", helloHandler)
    mux.HandleFunc("/world", worldHandler)

    server := http.Server
        Addr: ":8081",
        Handler: mux,
    
	server.ListenAndServe()

此时访问:

- localhost:8081/hello:会响应helloHandler函数。
- localhost:8081/hello/:会响应mainHandler函数。

在使用`ServeMux时:

  • 如果pattern以"/"开头,表示匹配URL的路径部分
  • 如果pattern不以"/"开头,表示从host开始匹配
  • 匹配时长匹配优先于短匹配,注册在"/"上的pattern会被所有请求匹配,但其匹配长度最短
  • 如果pattern带上了尾随斜线"/“,ServeMux将会对请求不带尾随斜线的URL进行301重定向。例如,在”/images/“模式上注册了一个handler,当请求的URL路径为”/images"时,将自动重定向为"/images/“,除非再单独为”/images"模式注册一个handler。
  • 如果为"/images"注册了handler,当请求URL路径为"/images/"时,将无法匹配到

示例:

/test/          注册  handler1
/test/thumb/    注册  handler2

如果请求的url是:/test/thumb/,则调用handler2
如果请求的url是:/test/list/,则调用handler1

注意:其实当代码中不显式的创建serveMux对象,http包就默认创建一个DefaultServeMux对象用来做路由管理器mutilplexer。

5 中间件

很多场景中,路由的处理函数在执行前,要先进行一些校验,比如安全检查,错误处理等等,这些行为需要在路由处理函数执行前有限执行。

package main


import(
	"fmt"
	"net/http"
)

func before(handle http.HandlerFunc) http.HandlerFunc 
	return func(w http.ResponseWriter, r * http.Request) 
		fmt.Println("执行前置处理")
		handle(w, r)
	


func test(w http.ResponseWriter, r *http.Request) 
	fmt.Fprintf(w, "test1")



func main() 

	http.HandleFunc("/", before(test))

	server := http.Server
		Addr: "127.0.0.1:8081",
	
	server.ListenAndServe()



以上是关于1 GO语言初探web开发与ServeMux与中间件的主要内容,如果未能解决你的问题,请参考以下文章

1 GO语言初探web开发与ServeMux与中间件

1 GO语言初探web开发与ServeMux与中间件

Go web开发初探

go语言 http学习

gRPC服务开发和接口测试初探Go

gRPC服务开发和接口测试初探「Go」