快速上手GO的net/http包,個人學習筆記

更多個人筆記:(僅供參考,非盈利)
gitee: https://gitee.com/harryhack/it_note
github: https://github.com/ZHLOVEYY/IT_note

針對GO中net/http包的學習筆記

基礎快速了解

創建簡單的GOHTTP服務

func main() {  http.HandleFunc("/hello", sayHello)  http.ListenAndServe(":8080", nil) //創建基本服務  
}  func sayHello(w http.ResponseWriter, r *http.Request) {  w.Write([]byte("Hello, World!"))  
}

訪問8080/hello進行測試

Handler接口定義:(這部分后面又詳細解釋)

type Handler interface {  ServeHTTP(ResponseWriter, *Request)  
}
//只要有ServeHTTP方法就行

可以自己實現這個接口

同時http提供了handlerFunc結構體

type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
//本質上就是調用自身,因為也是一個函數,不過serveHTTP的內容自己可以定義改動

和之前的HandleFunc區分,HandleFunc是用來給不同路徑綁定方法的,少一個r

那么只要滿足Handlerfunc 的簽名形式,就可以進行類型轉換

  • 類型轉換的正常的理解例子
type yes func(int, int) int  
func (y yes) add(a, b int) int {  return a + b  
}  
func multiply(a, b int) int {  fmt.Println(a * b)return a * b  
}  
func main() {  multiply(1, 2)   //2ans := yes(multiply) //將multiply進行轉換  res := ans.add(1, 2)  fmt.Println(res)   //3
}
http.HandleFunc("/hello", hello)

這個后面的簽名只要是 func(ResponseWriter, *Request)就可以了
但是

http.ListenAndServe(":8080", referer)

這個后面的函數需要是滿足Handler接口,有serveHTTP方法

嘗試搭建檢測是在query中有name = red
即http://localhost:8080/hello?name=red
發現會有重復覆蓋路由的問題,因為listenandServe會攔截所有的路由,后面再解決


type CheckQueryName struct {wantname stringhandler  http.Handler
}func (this *CheckQueryName) ServeHTTP(w http.ResponseWriter, r *http.Request) {queryParams := r.URL.Query() //獲取get請求的queryname := queryParams.Get("name")if name == "red" {this.handler.ServeHTTP(w, r) //其實就是調用本身,下面變為checkforname了} else {w.Write([]byte("not this name"))}
}func checkforname(w http.ResponseWriter, r *http.Request) {w.Write([]byte("check is ok"))
}func hello(w http.ResponseWriter, r *http.Request) {w.Write([]byte("hello"))
}func main() {thecheck := &CheckQueryName{ //用&因為serveHTTP方法定義在指針接收器上wantname: "red",handler:  http.HandlerFunc(checkforname),}http.HandleFunc("/hello", hello)       //滿足func(ResponseWriter, *Request)簽名就可以http.ListenAndServe(":8080", thecheck) //直接監視8080的所有端口,攔截所有路由
}
編寫簡單的GET請求客戶端

利用defaultclient或者自己定義client都可以

func main() {resp, err := http.DefaultClient.Get("https://api.github.com")if err != nil {panic(err)}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)if err != nil {panic(err)}fmt.Println(string(body))time.Sleep(time.Second * 2)  //等待獲取請求
}

但是如果把網址換成baidu.com就會獲取不到,這是因為轉發,以及沒有User-agent的問題

編寫自定義的GET請求客戶端

利用http.Client可以進行自定義

func main() {client := &http.Client{// 允許重定向CheckRedirect: func(req *http.Request, via []*http.Request) error {return nil},}req, err := http.NewRequest("GET", "https://www.baidu.com", nil)if err != nil {panic(err)}// 添加請求頭req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")resp, err := client.Do(req) //do執行HTTP請求的整個周期包括請求準備,建立連接,發送請求,請求重定向,接收響應等等defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)if err != nil {panic(err)}fmt.Println(string(body))time.Sleep(time.Second * 2)
}

發現可以接受到baidu的網頁html信息

編寫默認的post請求客戶端
func main() {postData := strings.NewReader(`{"name": "張三", "age": 25}`)resp, err := http.DefaultClient.Post("http://localhost:8080/users","application/json",  postData,)if err != nil {fmt.Printf("POST請求失敗: %v\n", err)return}defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)fmt.Printf("POST響應: %s\n", string(body))
}

string.NewReader是一種方法將格式改為io reader可以讀取的形式,接收的話也可以postData.Read讀取。
這一類的方式比較多,不一一匯總

對應的server.go (需要在終端中go run server.go )兩個終端分別運行服務端,客戶端

func main() {// 處理 /users 路徑的 POST 請求http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {// 只允許 POST 方法if r.Method != http.MethodPost {w.WriteHeader(http.StatusMethodNotAllowed)fmt.Fprintf(w, "只支持 POST 方法")return}// 讀取請求體body, err := ioutil.ReadAll(r.Body)if err != nil {w.WriteHeader(http.StatusBadRequest)fmt.Fprintf(w, "讀取請求失敗: %v", err)return}defer r.Body.Close()// 解析 JSON 數據,放入user中var user Userif err := json.Unmarshal(body, &user); err != nil {w.WriteHeader(http.StatusBadRequest) //寫入狀態碼fmt.Fprintf(w, "JSON 解析失敗: %v", err)return}// 設置響應頭w.Header().Set("Content-Type", "application/json")// 構造響應數據response := map[string]interface{}{"message": "success","data": map[string]interface{}{"name": user.Name,"age":  user.Age,},}// 返回 JSON 響應json.NewEncoder(w).Encode(response) //將 response 對象轉換為 JSON 格式并寫入響應//等價于:// jsonData, err := json.Marshal(response)// if err != nil {// 	w.WriteHeader(http.StatusInternalServerError)// 	return// }// w.Write(jsonData)})// 啟動服務器fmt.Println("服務器啟動在 :8080 端口...")if err := http.ListenAndServe(":8080", nil); err != nil {panic(err)}
}

多路復用器

DefaultServeMux一般不會使用,因為會有沖突等等問題,所以一般用NewServeMux直接創建

type apiHandler struct{}func (apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")fmt.Fprintf(w, `{"message": "API response"}`)
}func main() {mux := http.NewServeMux()mux.Handle("/api/", apiHandler{})  //多引入結構體,后面會知道有好處// mux.HandleFunc("/api/", func(w http.ResponseWriter, req *http.Request) {//     w.Header().Set("Content-Type", "application/json")//     fmt.Fprintf(w, `{"message": "API response from HandleFunc"}`)// })   //和上面等效mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {if req.URL.Path != "/" {http.NotFound(w, req)return}fmt.Fprintf(w, "Welcome to the home page!")})fmt.Println("Server running on :8080")http.ListenAndServe(":8080", mux)//用server:= &http.Server創建地址和handler,然后server.ListenAndServe也是一種表現方式}

mux和http.HandleFunc()的區別:
mux 可以創建多個路由器實例,用于不同的目的。同時可以為不同的路由器配置不同的中間件(用著先)

第三方有庫httprouter,比如可以解決url不能是變量代表的問題,了解就行
更多都是使用restful API進行開發的~目前的了解有個概念就行

處理器函數

Handle

注冊處理器過程中調用的函數:Handle

type username struct {name string
}func (this *username) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "%s", this.name)
}func main() {mux := http.NewServeMux()mux.Handle("/jack", &username{name: "jack"}) //會調用對應的serveHTTP方法mux.Handle("/lily", &username{name: "lily"})//可以為不同的路徑使用相同的處理器結構體,但傳入不同的參數//這就是比用handleFunc()更靈活的地方server := &http.Server{Addr:    ":8080",Handler: mux,}if err := server.ListenAndServe(); err != nil { //防止錯誤panic(err)}
}
HandlleFunc

處理器函數:HandleFunc
(注意不是HandlerFunc,沒有r !! HandleFunc 是處理器函數)
之前已經學習過,定義就是
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

深入源代碼會發現內部也是借助serveMux對象,從而實現了Handler的ServeHTTP()方法的

Handler

Handler就是處理器接口,實現ServeHTTP方法的,之前展示過

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

HandlerFunc是結構體,用于實現接口的
定義:

type HandlerFunc func(ResponseWriter, *Request)

用于連接處理器Handle和處理器函數HandleFunc,它實現了 Handler 接口,使得函數可以直接當作處理器使用:

  • 理解“連接連接處理器Handle和處理器函數HandleFunc”:(之前也學過)
// 方式一:普通函數
func hello(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello!")
}
// 注冊方式一:將函數轉換為 HandlerFunc
http.Handle("/hello", http.HandlerFunc(hello))// 方式二:直接使用 HandleFunc
http.HandleFunc("/hello", hello)

處理請求

請求分為:請求頭,請求URL,請求體等

html表單的enctype屬性

在postman的body部分可以查看

  • application/x-www-form-urlencode
    url方式編碼,較為通用,get和post都可以用
  • multipart/form-data
    通常適配post方法提交
  • text/plain
    適合傳遞大量數據

ResponseWriter接口涉及方法

  • 補充:
    fmt.Fprint和fmt.Fprintln能夠寫入ResponseWriter是因為ResponseWriter實現了io.Writer接口,fmt.Fprint/Fprintln將數據按格式轉換為字節流(如字符串、數字等),最終調用io.Writer的Write方法
Writeheader

curl -i localhost:8080/noAuth 或者使用postman進行驗證

func noAuth(w http.ResponseWriter, r *http.Request) {w.WriteHeader(401)fmt.Fprint(w, "沒有授權,你需要認證后訪問")
}func main() {http.HandleFunc("/noAuth", noAuth)err := http.ListenAndServe(":8080", nil)if err != nil {fmt.Println(err)}
}
Header

調用了Writeheader后的話就不能對響應頭進行修改了
curl -i http://localhost:8081/redirect (可以直接看到301)或者postman驗證

  • 重定向代碼
func Redirect(w http.ResponseWriter, r *http.Request) {w.Header().Set("Location", "http://localhost:8080/hello")// 必須使用包括http的完整的URL!w.WriteHeader(301)
}
func main() {http.HandleFunc("/redirect", Redirect)if err := http.ListenAndServe(":8081", nil); err != nil {panic(err)}
}
  • 主服務代碼
func sayHello(w http.ResponseWriter, r *http.Request) {w.Write([]byte("hello !!"))
}func main() {http.HandleFunc("/hello", sayHello)http.ListenAndServe(":8080", nil) //創建基本服務
}
write

之前都有demo,就是寫入返回,注意需要是[]byte()這樣的表示形式
如果不知道content-type格式可以通過數據的前512 比特進行確認

除了一般的文本字符串之外,還可以返回html和json,下面給出json的示范

type language struct {Language string `json:"language"` //反引號// 字段名首字母需要大寫才能被 JSON 序列化!!!!
}func uselanguage(w http.ResponseWriter, r *http.Request) {uselanguageis := language{Language: "en"}message, err := json.Marshal(uselanguageis)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json") //通過json形式傳遞w.Write(message)
}func main() {http.HandleFunc("/lan", uselanguage)if err := http.ListenAndServe(":8080", nil); err != nil {panic(err)}
}

注意一些格式上的細節,比如字段名首字母需要大寫才能被 JSON 序列化

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78697.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI-Browser適用于 ChatGPT、Gemini、Claude、DeepSeek、Grok的客戶端開源應用程序,集成了 Monaco 編輯器。

一、軟件介紹 文末提供程序和源碼下載學習 AI-Browser適用于 ChatGPT、Gemini、Claude、DeepSeek、Grok、Felo、Cody、JENOVA、Phind、Perplexity、Genspark 和 Google AI Studio 的客戶端應用程序,集成了 Monaco 編輯器。使用 Electron 構建的強大桌面應用程序&a…

Dify框架面試內容整理-Dify如何處理知識庫的集成?

Dify 在知識庫集成方面采用了“檢索增強生成(RAG)”的技術架構,核心實現思路如下: 一、知識庫集成的整體流程 Dify處理知識庫集成通常包括以下關鍵步驟: 文檔上傳↓

Laravel 模型使用全局作用域和局部作用域

一. 需要解決什么問題 最近Laravel 項目中遇到一個需求,我有一個客戶表,每個員工都有自己的客戶,但是自己只能看自己的客戶。 項目中,有很多功能需要查詢客戶列表,客戶詳情,查詢客戶入口很多,…

【Nova UI】十二、打造組件庫之按鈕組件(上):邁向功能構建的關鍵一步

序言 在上一篇文章中,我們深入探索了 icon 組件從測試到全局注冊的全過程🎯,成功為其在項目中穩定運行筑牢了根基。此刻,組件庫的建設之旅仍在繼續,我們將目光聚焦于另一個關鍵組件 —— 按鈕組件。按鈕作為用戶與界面…

鴻蒙OSS文件(視頻/圖片)壓縮上傳組件-能夠增刪改查

一、鴻蒙實現處理-壓縮上傳整體代碼處理邏輯 轉沙箱壓縮獲取憑證并上傳文件 文件準備(拿到文件流)獲取上傳憑證(調接口1拿到file_name和upload_url)執行文件上傳(向階段2拿到的upload_url上傳文件)更新列表…

河道流量監測,雷達流量計賦能水安全智慧守護

在蜿蜒的河道之上,水流的脈搏始終與人類文明的興衰緊密相連。從農田灌溉的水量調配到城市防洪的精準預警,從生態保護的水質溯源到水資源管理的決策,河道流量監測如同大地的 “血管檢測”,是守護水安全的第一道防線。傳統監測手段在…

CSS3 基礎(邊框效果)

一、邊框效果 屬性功能示例值說明border-radius創建圓角border-radius: 20px;設置元素的圓角半徑,支持像素(px)或百分比(%)。值為 50% 時可變為圓形。box-shadow添加陰影box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.5)…

零基礎小白如何上岸數模國獎

零基礎小白如何上岸數模國獎 我自己本人第一次參加數模國賽順利上岸國獎,當然那段經歷也是比較痛苦了,差不多也是從當年四月開始接觸數學建模,第一次參加媽媽杯成績并不理想,后面不斷參加數模比賽進行模擬,最后順利上岸…

SQL學習-常用函數

常見SQL函數使用 (注意:不同的數據庫類型使用的語法不同) 以下是MySQL和PostgreSQL在實現替換、抽取、拼接、分列四個常見字符串操作功能時的核心區別總結,按功能分類對比: 1. 替換(Replace) …

rt-linux下的cgroup cpu的死鎖bug

一、背景 rt-linux系統有其非常大的實時性的優勢,但是與之俱來的是該系統上有一些天然的缺陷。由于rt-linux系統允許進程在內核態執行的邏輯里,在持鎖期間,甚至持spinlock鎖期間,都能被其他進程搶占。這一特性能帶來實時性的好處…

java—12 kafka

目錄 一、消息隊列的優缺點 二、常用MQ 1. Kafka 2. RocketMQ 3. RabbitMQ 4. ActiveMQ 5. ZeroMQ 6. MQ選型對比 適用場景——從公司基礎建設力量角度出發 適用場景——從業務場景角度出發 四、基本概念和操作 1. kafka常用術語 2. kafka常用指令 3. 單播消息&a…

14【模塊學習】74HC595:使用學習

74HC595 1、74HC595簡介2、代碼演示2.1、驅動8位流水燈 3、74HC595級聯3.1、驅動16位流水燈3.2、驅動8位數碼管3.3、驅動8x8點陣屏幕3.4、8x8點陣屏幕滾動顯示 1、74HC595簡介 在51單片機中IO引腳資源十分的緊缺,所以常常需要使用75HC595芯片進行驅動那些需要占用多…

JAVA后端開發常用的LINUX命令總結

一、Linux常用命令大全(2025年最新版) 常用 Linux 命令 文件和目錄管理: cd:用于切換當前工作目錄,如cd /home/user。mkdir:創建新目錄,mkdir -p /home/user/mydir可遞歸創建多級目錄。pwd&am…

uniapp-商城-40-shop 購物車 選好了 進行訂單確認4 配送方式3 地址編輯

前面說了配送 和地址頁面 當地址頁面為空或需要添加地址時&#xff0c;需要添加地址。 我的地址頁面有個按鈕 就是添加地址 點擊 添加地址 按鈕 后&#xff0c;就會跳轉到地址添加的頁面 1、添加地址頁面 2、添加地址文件夾以及文件的創建 3、添加地址的代碼 <template…

現場問題排查-postgresql某表索引損壞導致指定數據無法更新影響卷宗材料上傳

問題現象 今天突然被拉進一個群&#xff0c;說某地區友商推送編目結果報錯&#xff0c;在我們自己的卷宗系統上傳材料也一直轉圈&#xff0c;也刪除不了案件卷宗&#xff0c;重置模板也沒用&#xff0c;只有個別案件有問題。雖然這事兒不屬于我負責&#xff0c;但還是抽時間給…

Redis01-基礎-入門

零、文章目錄 Redis01-基礎-入門 1、認識 NoSQL NoSQL 知識請參考&#xff1a;https://blog.csdn.net/liyou123456789/article/details/132612444 2、認識 Redis &#xff08;1&#xff09;簡介 Redis&#xff08;Remote Dictionary Server&#xff0c;遠程字典服務&…

【嘉立創EDA】如何在更新或轉換原理圖到PCB時,保留已有布局器件

文章路標?? :one: 文章解決問題:two: 主題內容:three: 參考方法be end..1?? 文章解決問題 操作環境:嘉立創EDA專業版 V2.2.37 本文使用嘉立創EDA,描述在更新或轉換原理圖到PCB時,保留已有布局器件的方法。本文將此過程記錄,以供有需要的讀者參考。 2?? 主題內容 …

03 APQC PROCESS CLASSIFICATION FRAMEWORK (PCF)

APQC流程分類框架&#xff08;APQC Process Classification Framework, PCF&#xff09;最初由美國生產力與質量中心&#xff08;American Productivity & Quality Center, APQC&#xff09;開發&#xff0c;旨在用于跨組織的流程性能基準比較。現在&#xff0c;它也常被用…

分析型數據庫入門指南:如何選擇適合你的實時分析工具?

一、什么是分析型數據庫&#xff1f;為什么需要它&#xff1f; 據Gartner最新報告顯示&#xff0c;超過75%的企業現已在關鍵業務部門部署了專門的分析型數據庫&#xff0c;這一比例還在持續增長。 隨著數據量呈指數級增長&#xff0c;傳統數據庫已無法滿足復雜分析場景的需求…

body Param Query 三個 不同的入參 分別是什么意思 在前端 要怎么傳 這三種不同的參數

在 NestJS 中&#xff0c;Body()、Param() 和 Query() 用于處理不同類型的請求參數。以下是它們的含義及前端傳遞方式&#xff1a; Body()&#xff1a;請求體參數 ? 含義&#xff1a;用于獲取請求體中的數據&#xff08;如 POST/PUT 請求中提交的 JSON、表單數據等&#xff09…