手把手和你一起實作一個Web框架實戰——EzWeb框架(一)[Go語言筆記]Go專案實戰
代碼倉庫:
github
gitee
本篇代碼請選擇分支demo1

中文注釋,非常詳盡可以配合食用
本篇設計說明草圖:

一、Golang中的net/http標準庫如何處理一個請求
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/count", counter)
log.Fatal(http.ListenAndServe("localhost:9090", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}
標準庫中實作了監聽,映射路由,和決議http報文,
瀏覽器的請求,http.ListenAndServe方法中,第一個引數是監聽地址響,第二個引數代表處理所有的HTTP請求的實體,nil代表使用標準庫中的實體處理,
我們通過第二個引數,轉入到我們的實體,這樣所有的HTTP請求就都交給了我們的實體來處理,
二、實作http.Handler介面
/*
@Time : 2021/8/5 下午4:08
@Author : mrxuexi
@File : main
@Software: GoLand
*/
package main
import (
"fmt"
"log"
"net/http"
)
type Engine struct {}
/**
* @Description:
對Engine結構體的ServeHttp方法實作,ServeHTTP是Handler介面中的一個方法,在這里我們對這個方法進行實作,放入到我們的Engine中,這里就用上了我們的自定義方法來處理請求,
* @receiver engine
* @param w http.ResponseWriter(通過該ResponseWriter構造針對該請求的回應)
* @param req *http.Request(Request中包括了發送來的HTTP請求的全部資訊)
*/
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)
//此處后者的引數填入engine,讓請求交由我們實作的engine實體來處理
log.Fatal(http.ListenAndServe(":9090",engine))
}
三、實作簡單的GET,POST方法,實作框架簡單原型
設計自己的Engine結構體,然后將原來啟動web專案的
log.Fatal(http.ListenAndServe(":9090",engine))
封裝成Run(addr),并將第二個引數的默認實體,直接寫為我們的engine實體,
func (engine *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, engine)
}
這里engine涉及到一個轉換,實作了介面方法的struct轉換為介面型別
我們要實作的GET,POST方法,作用是,將路由和方法,注冊進來,然后在監聽的時候進行查找和處理,
這里設計一個router放入到我們的Engine結構體中:
// Engine 實作了"net/http"標準庫中的 Handler 介面中的ServeHTTP方法
type Engine struct {
//用于存盤路由處理方法
//key是方法型別加路徑,value是用戶的處理方法
router map[string]HandlerFunc
}
我們的GET和POST方法就是這樣實作的,呼叫addRoute方法,將路由和回應方法存入到router中:
// GET 實作的是Engine的處理GET請求的方法,注冊到router中
func (engine *Engine) GET(path string, handler HandlerFunc) {
engine.addRoute("GET", path, handler)
}
// POST 同上
func (engine *Engine) POST(path string, handler HandlerFunc) {
engine.addRoute("POST", path, handler)
}
這里就是addRoute方法,method-path作為key,handler作為value
// Engine 中 addRoute 方法,在 router map[string]HandlerFunc 中存入對應處理方法
//存入形式為例如:{ "GET-/index" : 定義的處理方法 }engine
func (engine *Engine) addRoute(method string, path string, handler HandlerFunc) {
key := method + "-" + path
engine.router[key] = handler
}
我們再重寫Handler介面中的ServeHTTP方法,通過req請求的路由查找router中注冊的方法執行,
// ServeHTTP 方法的實作,用于實作處理HTTP請求
// 先決議req對應傳入的路徑,查找router中,如果有相應的處理方法,則執行處理方法,如果沒有則回傳找不到的提示
// 來自Handler介面
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
//根據請求req中的資料,從router中取出對應的方法
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
fmt.Fprintf(w, "could not find the route: %s\n", req.URL)
}
}
雛形的全部原始碼:
/*
@Time : 2021/8/16 下午4:03
@Author : Mrxuexi
@File : Ez
@Software: GoLand
*/
package Ez
import (
"fmt"
"net/http"
)
// HandlerFunc 是Ez框架中定義的對請求的回應處理方法,默認傳入這兩個引數,針對http請求處理
type HandlerFunc func(http.ResponseWriter, *http.Request)
// Engine 實作了"net/http"標準庫中的 Handler 介面中的ServeHTTP方法
type Engine struct {
//用于存盤路由處理方法
//key是方法型別加路徑,value是用戶的處理方法
router map[string]HandlerFunc
}
// ServeHTTP 方法的實作,用于實作處理HTTP請求
// 先決議req對應傳入的路徑,查找router中,如果有相應的處理方法,則執行處理方法,如果沒有則回傳找不到的提示
// 來自Handler介面
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
//根據請求req中的資料,從router中取出對應的方法
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
fmt.Fprintf(w, "could not find the route: %s\n", req.URL)
}
}
// New 是Ez.Engine的建構式
func New() *Engine {
return &Engine{router: make(map[string]HandlerFunc)}
}
// Engine 中 addRoute 方法,在 router map[string]HandlerFunc 中存入對應處理方法
//存入形式為例如:{ "GET-/index" : 定義的處理方法 }engine
func (engine *Engine) addRoute(method string, path string, handler HandlerFunc) {
key := method + "-" + path
engine.router[key] = handler
}
// GET 實作的是Engine的處理GET請求的方法,注冊到router中
func (engine *Engine) GET(path string, handler HandlerFunc) {
engine.addRoute("GET", path, handler)
}
// POST 同上
func (engine *Engine) POST(path string, handler HandlerFunc) {
engine.addRoute("POST", path, handler)
}
// Run 用于啟動服務,直接制定用該路由的engine
func (engine *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, engine)
}
嘗試使用:
/*
@Time : 2021/8/16 下午4:01
@Author : mrxuexi
@File : main
@Software: GoLand
*/
package main
import (
"Ez"
"fmt"
"net/http"
)
func main() {
r := Ez.New()
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w,"Hello")
})
r.Run(":9090")
}
成功!
后續我們繼續完善內容

參考:
[1]: https://github.com/geektutu/7days-golang/tree/master/gee-web ""gee""
[2]: https://github.com/gin-gonic/gin ""gin""
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295965.html
標籤:Go
