1. HTTP

Kesa...大约 3 分钟golang

1. 使用标准库 net/http

func main() {
	// 注册路由
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/hello", helloHandler)

	// 监听并启动 HTTP 服务
	log.Fatal(http.ListenAndServe(":8000", nil))
}

func indexHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "URL.path = %q\n", req.URL.Path)
}

func helloHandler(w http.ResponseWriter, req *http.Request) {
	// 输出所有 http 请求头 request.Header
	for k, v := range req.Header {
		fmt.Fprintf(w, "Header[%q] =  %q\n", k, v)
	}
}
  • indexHandler:路由/绑定的处理函数,响应当前请求的 URL 路径
  • helloHandler:路由/hello 绑定的处理函数,响应当前请求的请求头
  • ListenAndServe(addr string, handler Handler):启动 Web 服务
    • addr:监听地址
    • handler:处理所有 HTTP 请求的实例,默认为 nil;可作为 Web 框架的入口
$ curl http://localhost:8000
URL.path = "/"
$ curl http://localhost:8000/hello
Header["User-Agent"] =  ["curl/8.0.1"]
Header["Accept"] =  ["*/*"]
Header["Accept-Encoding"] =  ["gzip"]

2. http.Handler接口

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

http.Handler是接口类型,只要自定义的类型实现了该接口,那么将自定义类型的实例作为ListenAndServe的第二个参数传入,该实例将接管所有的 HTTP 请求的处理。

// Engine is the uni handler for all request
type Engine struct{}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.URL.Path {
	case "/":
		fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
	case "/hello":
		for k, v := range req.Header {
			fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
		}
	default:
		fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
	}
}

func main() {
	engine := new(Engine)
	log.Fatal(http.ListenAndServe(":8000", engine))
}

  • Engine实现了http.Handler接口,其方法ServeHTTP有两个参数:
    • http.ResponseWriter:用于构造 HTTP Response
    • *http.Request:包含HTTP请求的所有信息
  • ListenAndServe函数的第二参数传入创建的Engine实例,接管所有的 HTTP 请求的处理

3. Gee 框架雏形

https://github.com/dreamjz/golang-notes/tree/main/books/7-days-golang/Gee/day1-basicopen in new window

重新组织上述代码,目录结构如下:

base3/
	gee/
  	|--gee.go
  	|--go.mod
main.go
go.mod

base3/go.mod:

module base3

go 1.20

require (
	gee v0.0.0
)
// 将 gee 指向 ./gee
replace gee => ./gee

(备注:在 gov1.18 及之后可以使用 go workspace 替代 replace 使用)

使用 go work

$ go work init .
$ go work use ./gee
// base3/go.work
go 1.20

use (
	.
	./gee
)

// base3/go.mod
// 使用了 go work,无需使用 replace
module base3

go 1.20

require (
	gee v0.0.0
)

3.1 gee.go

package gee

import (
	"fmt"
	"net/http"
)

// HandlerFunc defines the request handler used by gee engine
type HandlerFunc func(http.ResponseWriter, *http.Request)

// Engine implement the http.Handler
type Engine struct {
	router map[string]HandlerFunc
}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	key := req.Method + "-" + req.URL.Path
	if handler, ok := engine.router[key]; ok {
		handler(w, req)
	} else {
		fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
	}
}

func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {
	key := method + "-" + pattern
	engine.router[key] = handler
}

// GET  add GET request route
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
	engine.addRoute("GET", pattern, handler)
}

// POST  add POST request route
func (engine *Engine) POST(pattern string, handler HandlerFunc) {
	engine.addRoute("POST", pattern, handler)
}

// Run start a http server
func (engine *Engine) Run(addr string) error {
	return http.ListenAndServe(addr, engine)
}

// New is the constructor of gee.Engine
func New() *Engine {
	return &Engine{
		router: map[string]HandlerFunc{},
	}
}

  • HandlerFunc:自定义的请求处理函数,交由调用方实现
  • Engine.router:路由表,绑定请求方法及路径和对应的处理函数
  • *Engine.addRoute:添加新的路由映射到路由表中
  • *Engine.Run:封装http.ListenAndServe函数
  • *Engine.ServeHTTP:实现的http.Handler接口方法,根据请求获取对应的处理函数,路由表中不存在则返回 404

3.2 main.go

package main

import (
	"fmt"
	"gee"
	"net/http"
)

func main() {
	r := gee.New()

	r.GET("/", func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
	})
	r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
		for k, v := range req.Header {
			fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
		}
	})

	r.Run(":8000")
}

流程如下:

  1. 创建 gee.Engine实例
  2. 注册路由,//hello
  3. 启动 HTTP 服务

启动并测试

$ curl http://localhost:8000
URL.path = "/"
$ curl http://localhost:8000/hello
Header["User-Agent"] =  ["curl/8.0.1"]
Header["Accept"] =  ["*/*"]
Header["Accept-Encoding"] =  ["gzip"]
$ curl http://localhost:8000/path
404 NOT FOUND: /path

4. 小结

现阶段 Gee 的雏形已完成,实现了以下功能:

  1. 路由映射表
  2. 注册静态路由
  3. 启动 HTTP 服务

Reference

  1. https://geektutu.com/post/gee-day1.htmlopen in new window
  2. https://go.dev/doc/tutorial/workspacesopen in new window
上次编辑于:
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.2