最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Go語言自制簡(jiǎn)單易用的Web框架

 更新時(shí)間:2024年01月15日 10:50:49   作者:dpwgc  
這篇文章主要為大家詳細(xì)介紹了如何使用Go語言實(shí)現(xiàn)自制簡(jiǎn)單易用的Web框架,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

為什么寫這玩意

有時(shí)我要寫一些很小的應(yīng)用,比如爬蟲后端、服務(wù)器腳本又或者是BFF服務(wù),需要簡(jiǎn)單的Web服務(wù)。用gin感覺有點(diǎn)重,go.mod里會(huì)有很多用不到的依賴,直接用httprouter又很麻煩。所以想整個(gè)簡(jiǎn)單易用的Web框架。在實(shí)現(xiàn)基礎(chǔ)能力的同時(shí),順便集成一些方便開發(fā)的功能(便捷的Websocket連接、SSE推送、自動(dòng)綁定請(qǐng)求數(shù)據(jù)、自動(dòng)序列化返回響應(yīng)數(shù)據(jù)),并且盡量不引入第三方依賴,保持極簡(jiǎn)架構(gòu)。

大概的架構(gòu)圖

技術(shù)選型

  • 底層HTTP路由:選擇httprouter。
  • 將請(qǐng)求頭/表單/URI參數(shù)綁定到結(jié)構(gòu)體上:選擇mapstructure。

框架目前的go.mod依賴情況:

module github.com/dpwgc/easierweb

go 1.21.4

require (
   github.com/julienschmidt/httprouter v1.3.0
   github.com/mitchellh/mapstructure v1.5.0
   golang.org/x/net v0.17.0
   gopkg.in/yaml.v3 v3.0.1
)

基本用法

首先,運(yùn)行g(shù)o get,安裝一下框架:

go get github.com/dpwgc/easierweb

然后,編寫路由代碼,寫起來和gin差不多,沒有學(xué)習(xí)成本:

package main

import (
   "github.com/dpwgc/easierweb"
   "github.com/dpwgc/easierweb/middlewares"
   "log"
   "net/http"
)

func main() {

   // 新建一個(gè)路由
   router := easierweb.New()
   
   // 使用日志中間件
   router.Use(middlewares.Logger())
   
   // GET接口
   router.GET("/hello/:name", hello)
   
   // 啟動(dòng)服務(wù)
   log.Fatal(router.Run(":80"))
}

// 請(qǐng)求處理函數(shù)
func hello(ctx *easierweb.Context) {

   // 獲取URI Path里的name參數(shù)
   name := ctx.Path.Get("name")
   
   // 綁定URI Query參數(shù)到指定結(jié)構(gòu)體上
   req := Request{}
   err := ctx.BindQuery(&req)
   if err != nil {
      panic(err)
   }
   
   fmt.Println("request data:", req)
   
   // 響應(yīng):hello {name}
   ctx.WriteString(http.StatusOK, "hello "+name)
}

// 請(qǐng)求結(jié)構(gòu)體
type Request struct {
   Name   string `mapstructure:"name"`
   Mobile string `mapstructure:"mobile"`
}

進(jìn)階改造(將繁瑣的流程自動(dòng)化)

實(shí)際在使用的時(shí)候,每次獲取請(qǐng)求數(shù)據(jù)都得調(diào)用一下Bind函數(shù),然后響應(yīng)數(shù)據(jù)時(shí)又得調(diào)用下Write函數(shù)再return,感覺還是不夠簡(jiǎn)單,因此加了個(gè)通過反射自動(dòng)綁定請(qǐng)求數(shù)據(jù)到結(jié)構(gòu)體、自動(dòng)序列化寫入響應(yīng)數(shù)據(jù)的功能。

實(shí)現(xiàn)方式參考: github.com/MikeLINGxZ/simple-server-runner 這是一個(gè)基于Gin的自動(dòng)綁定請(qǐng)求數(shù)據(jù)+自動(dòng)寫入響應(yīng)數(shù)據(jù)的庫。

最終成品有點(diǎn)像Spring Boot那種接口方法樣式:

package main

import (
   "fmt"
   "github.com/dpwgc/easierweb"
   "github.com/dpwgc/easierweb/middlewares"
   "log"
)

func main() {
	
   // 還是老樣子,先創(chuàng)建一個(gè)路由
   router := easierweb.New().Use(middlewares.Logger())
   
   // 使用EasyPOST函數(shù)(EasyXXX函數(shù)內(nèi)置了自動(dòng)綁定+自動(dòng)寫入),整一個(gè)POST提交接口
   router.EasyPOST("/submit", submit)
   
   // 啟動(dòng)服務(wù)
   log.Fatal(router.Run(":80"))
}

// 請(qǐng)求處理函數(shù)(自動(dòng)綁定請(qǐng)求數(shù)據(jù)+自動(dòng)寫入響應(yīng)數(shù)據(jù))
// 這個(gè)請(qǐng)求處理函數(shù)和上文的基礎(chǔ)版不大一樣,除了上下文入?yún)⒁酝?,還有個(gè)請(qǐng)求數(shù)據(jù)入?yún)⒑晚憫?yīng)數(shù)據(jù)返回體
// 當(dāng)這個(gè)函數(shù)被調(diào)用時(shí),會(huì)通過反射將POST請(qǐng)求的Body數(shù)據(jù)自動(dòng)解析并綁定到req參數(shù)上(如果是GET請(qǐng)求就綁定Query參數(shù))
// 當(dāng)這個(gè)函數(shù)返回時(shí),同樣通過反射獲取到返回的結(jié)構(gòu)體,將其序列化成Json字符串后,寫入響應(yīng)
func submit(ctx *easierweb.Context, req Request) *Response {
	
   // 打印req的參數(shù)
   fmt.Printf("json body -> name: %s, mobile: %s \n", req.Name, req.Mobile)
   
   // 直接return結(jié)構(gòu)體
   return &Response{Code: 1000, Msg:  "hello"}
}

type Request struct {
   Name   string `json:"name"`
   Mobile string `json:"mobile"`
}

type Response struct {
   Code int    `json:"code"`
   Msg  string `json:"msg"`
}

請(qǐng)求入?yún)⒑晚憫?yīng)返回值在反射賦值/取值時(shí)都做了動(dòng)態(tài)化識(shí)別,可傳可不傳,不傳req入?yún)r(shí)就不會(huì)自動(dòng)綁定請(qǐng)求數(shù)據(jù),不返回Response且沒有報(bào)錯(cuò)時(shí)就響應(yīng)204,返回了error或者函數(shù)拋出異常了就返回400/500,Response可以是對(duì)象也可以是切片。

func TestAPI(ctx *easierweb.Context, req Request) (*Response, error)
func TestAPI(ctx *easierweb.Context, req Request) *Response
func TestAPI(ctx *easierweb.Context, req Request) error
func TestAPI(ctx *easierweb.Context, req Request)
func TestAPI(ctx *easierweb.Context) (*Response, error)
func TestAPI(ctx *easierweb.Context) *Response
func TestAPI(ctx *easierweb.Context) error
func TestAPI(ctx *easierweb.Context)

實(shí)際開發(fā)中,不一定以Json格式來接收/呈現(xiàn)數(shù)據(jù),所以留了個(gè)插件口子,可以讓用戶自定義自動(dòng)綁定/寫入數(shù)據(jù)的序列化與反序列化方式。

// 使用XML格式來處理自動(dòng)綁定和自動(dòng)寫入的數(shù)據(jù)
router := easierweb.New(easierweb.RouterOptions{
   RequestHandle: plugins.XMLRequestHandle(),
   ResponseHandle: plugins.XMLResponseHandle(),
})

追加功能(常用方法封裝)

我寫瀏覽器Js爬蟲經(jīng)常要用Websocket來連接后端并持續(xù)傳輸數(shù)據(jù),還有些表單動(dòng)態(tài)賦值的需求經(jīng)常要用到SSE,那就順便給框架整個(gè)websocket和SSE的快捷使用方式,同時(shí)把連接升級(jí)、跨域、SSE請(qǐng)求頭設(shè)置、連接關(guān)閉之類的操作全部都封裝到底層,不需要使用者操心這么多事情。

func main() {

   // 新建路由
   router := easierweb.New()
   
   // 快速使用websocket
   router.WS("/demoWS/:id", DemoWS)

   // 快速使用SSE
   router.SSE("/demoSSE/:id", DemoSSE)

   // 啟動(dòng)
   log.Fatal(router.Run(":80"))
}
// 快速使用websocket
func DemoWS(ctx *easierweb.Context) {

   // 處理websocket連接
   for {
   
      // 接收客戶端消息
      msg, err := ctx.ReceiveString()
      if err != nil {
         panic(err)
      }

      fmt.Println("read websocket msg:", msg)

      // 發(fā)送消息給客戶端
      err = ctx.SendString("hello")
      if err != nil {
         panic(err)
      }

      time.Sleep(1 * time.Second)

      // 函數(shù)返回時(shí),websocket連接會(huì)自動(dòng)關(guān)閉,不勞煩用戶手動(dòng)調(diào)close了
      return
   }
}
// 快速使用SSE
func DemoSSE(ctx *easierweb.Context) {

   // 循環(huán)推送數(shù)據(jù)
   for i := 0; i < 5; i++ {

      // SSE推送數(shù)據(jù), data: hello, id: {i}
      err := ctx.Push(fmt.Sprintf("data: hello\nid: %v\n\n", i))
      if err != nil {
         panic(err)
      }

      time.Sleep(1 * time.Second)
   }
}

以上就是使用Go語言自制簡(jiǎn)單易用的Web框架的詳細(xì)內(nèi)容,更多關(guān)于Go Web框架的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Windows上安裝Go并配置環(huán)境變量(圖文步驟)

    Windows上安裝Go并配置環(huán)境變量(圖文步驟)

    開始使用Go創(chuàng)建應(yīng)用程序之前,需要設(shè)置開發(fā)環(huán)境,本文主要介紹了Windows上安裝Go并配置環(huán)境變量,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • 深入解析Go語言中HTTP請(qǐng)求處理的底層實(shí)現(xiàn)

    深入解析Go語言中HTTP請(qǐng)求處理的底層實(shí)現(xiàn)

    本文將詳細(xì)介紹?Go?語言中?HTTP?請(qǐng)求處理的底層機(jī)制,包括工作流程、創(chuàng)建?Listen?Socket?監(jiān)聽端口、接收客戶端請(qǐng)求并建立連接以及處理客戶端請(qǐng)求并返回響應(yīng)等,需要的朋友可以參考下
    2023-05-05
  • Golang中間件設(shè)計(jì)示例詳解

    Golang中間件設(shè)計(jì)示例詳解

    這篇文章主要介紹了Golang中間件設(shè)計(jì)示例,中間件是在HTTP請(qǐng)求處理過程中,對(duì)請(qǐng)求進(jìn)行處理的一種模式,中間件可以在請(qǐng)求到達(dá)處理器之前或之后對(duì)請(qǐng)求進(jìn)行攔截,修改或者增強(qiáng),同時(shí)可以對(duì)響應(yīng)進(jìn)行處理,需要的朋友可以參考下
    2023-05-05
  • Go 語言中的select語句詳解及工作原理

    Go 語言中的select語句詳解及工作原理

    在Go語言中,select語句是用于處理多個(gè)通道(channel)操作的一種控制結(jié)構(gòu),它類似于 switch 語句,本文給大家介紹Go 語言中的select語句詳解及工作原理,感興趣的朋友一起看看吧
    2025-04-04
  • Go使用Viper庫讀取YAML配置文件的示例代碼

    Go使用Viper庫讀取YAML配置文件的示例代碼

    Viper是適用于Go應(yīng)用程序的完整配置解決方案,它被設(shè)計(jì)用于在應(yīng)用程序中工作,并且可以處理所有類型的配置需求和格式,本文給大家介紹了Go使用Viper庫讀取YAML配置文件的方法,需要的朋友可以參考下
    2024-05-05
  • Golang 數(shù)據(jù)庫操作(sqlx)和不定字段結(jié)果查詢

    Golang 數(shù)據(jù)庫操作(sqlx)和不定字段結(jié)果查詢

    本文主要介紹了Golang 數(shù)據(jù)庫操作(sqlx)和不定字段結(jié)果查詢,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • go語言interface接口繼承多態(tài)示例及定義解析

    go語言interface接口繼承多態(tài)示例及定義解析

    這篇文章主要為大家介紹了go語言interface接口繼承多態(tài)示例及定義解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go語言并發(fā)編程 互斥鎖詳情

    Go語言并發(fā)編程 互斥鎖詳情

    在并發(fā)編程中,多個(gè)Goroutine訪問同一塊內(nèi)存資源時(shí)可能會(huì)出現(xiàn)競(jìng)態(tài)條件,我們需要在臨界區(qū)中使用適當(dāng)?shù)耐讲僮鱽硪员苊飧?jìng)態(tài)條件。Go 語言中提供了很多同步工具,本文將介紹互斥鎖Mutex和讀寫鎖RWMutex的使用方法。
    2021-10-10
  • 解讀unsafe.Pointer和uintptr的區(qū)別

    解讀unsafe.Pointer和uintptr的區(qū)別

    這篇文章主要介紹了解讀unsafe.Pointer和uintptr的區(qū)別及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Go語言列表List獲取元素的4種方式

    Go語言列表List獲取元素的4種方式

    Golang的列表元素的獲取可以使用內(nèi)置的 Front 函數(shù)獲取頭結(jié)點(diǎn),使用 Back 函數(shù)獲取尾結(jié)點(diǎn),使用 Prev 獲取前一個(gè)結(jié)點(diǎn),使用 Next 獲取下一個(gè)結(jié)點(diǎn),本文就介紹了Go語言列表List獲取元素的4種方式,感興趣的可以了解一下
    2022-04-04

最新評(píng)論

武义县| 襄城县| 通化县| 永仁县| 阿克苏市| 永吉县| 河东区| 江北区| 铜川市| 辉县市| 安义县| 大洼县| 章丘市| 西畴县| 鹤壁市| 湟源县| 五莲县| 罗江县| 库伦旗| 怀集县| 福泉市| 个旧市| 治多县| 汉源县| 石渠县| 乐山市| 漳浦县| 辽中县| 磴口县| 雷波县| 固镇县| 汉沽区| 新化县| 花垣县| 灵璧县| 永和县| 上高县| 崇州市| 利津县| 广元市| 花莲县|