前言 本人最近幾年一直在學習並且實踐雲原生,也從測試轉型到DevOps,公司的所有服務也從數據中心搬到雲端,回顧過去幾年學到的知識,覺得是時候總結一下了,所以準備以雲原生為題材寫下這一過程中所有學到的知識點,希望對大家有所幫助。 在我帶你開始雲原生之旅前,需要入門一下golang,沒辦法,誰讓它是雲 ...
前言
本人最近幾年一直在學習並且實踐雲原生,也從測試轉型到DevOps,公司的所有服務也從數據中心搬到雲端,回顧過去幾年學到的知識,覺得是時候總結一下了,所以準備以雲原生為題材寫下這一過程中所有學到的知識點,希望對大家有所幫助。
在我帶你開始雲原生之旅前,需要入門一下golang,沒辦法,誰讓它是雲原生領域里正紅的發紫的“角兒,從最底層的 containerd,到編排層的 Kubernetes,再到如今正紅的發紫的 Istio,隨便拿出一個來都是golang寫的。我相信你學了Golang之後,會發現它非常好用,library豐富,部署簡單,容易上手,咱也不想成為資深開發,但我們自動化,寫工具之類的還是需要掌握一門語言的,我反正已經放棄其它學過的語言了。
本篇文章講述如何構建一個簡單的HTTP伺服器,Golang的標準庫net/http 讓這一切變得很容易,僅適用於golang新手(已瞭解過Golang語言特性)。
關鍵詞:Golang,入門,HTTP server,DevOps,雲原生,Golang 例子
Learning By Example
讓我們用Pizza餐廳點單作為例子,定義 Pizza 餐廳 API 3個endpoints 如下:
- Get 請求 - List all pizzas:
/pizzas
- POST 請求 - Make a pizza order:
/orders
- Get 請求 - List all orders:
/orders
代碼如下:
1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "net/http" 8 ) 9 10 type Pizza struct { 11 ID int `json:"id"` 12 Name string `json:"name"` 13 Price int `json:"price"` 14 } 15 16 type Pizzas []Pizza 17 18 func (ps Pizzas) FindByID(ID int) (Pizza, error) { 19 for _, pizza := range ps { 20 if pizza.ID == ID { 21 return pizza, nil 22 } 23 } 24 25 return Pizza{}, fmt.Errorf("couldn't find pizza with ID: %d", ID) 26 } 27 28 type Order struct { 29 PizzaID int `json:"pizza_id"` 30 Quantity int `json:"quantity"` 31 Total int `json:"total"` 32 } 33 34 type Orders []Order 35 36 type pizzasHandler struct { 37 pizzas *Pizzas 38 } 39 40 func (ph pizzasHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 41 w.Header().Set("Content-Type", "application/json") 42 43 switch r.Method { 44 case http.MethodGet: 45 if len(*ph.pizzas) == 0 { 46 http.Error(w, "Error: No pizzas found", http.StatusNotFound) 47 return 48 } 49 50 json.NewEncoder(w).Encode(ph.pizzas) 51 default: 52 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) 53 } 54 } 55 56 type ordersHandler struct { 57 pizzas *Pizzas 58 orders *Orders 59 } 60 61 func (oh ordersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 62 w.Header().Set("Content-Type", "application/json") 63 64 switch r.Method { 65 case http.MethodPost: 66 var o Order 67 68 if len(*oh.pizzas) == 0 { 69 http.Error(w, "Error: No pizzas found", http.StatusNotFound) 70 return 71 } 72 73 err := json.NewDecoder(r.Body).Decode(&o) 74 if err != nil { 75 http.Error(w, "Can't decode body", http.StatusBadRequest) 76 return 77 } 78 79 p, err := oh.pizzas.FindByID(o.PizzaID) 80 if err != nil { 81 http.Error(w, fmt.Sprintf("Error: %s", err), http.StatusBadRequest) 82 return 83 } 84 85 o.Total = p.Price * o.Quantity 86 *oh.orders = append(*oh.orders, o) 87 json.NewEncoder(w).Encode(o) 88 case http.MethodGet: 89 json.NewEncoder(w).Encode(oh.orders) 90 default: 91 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) 92 } 93 } 94 95 func main() { 96 var orders Orders 97 pizzas := Pizzas{ 98 Pizza{ 99 ID: 1, 100 Name: "Veggie", 101 Price: 12, 102 }, 103 Pizza{ 104 ID: 2, 105 Name: "Cheese", 106 Price: 11, 107 }, 108 Pizza{ 109 ID: 3, 110 Name: "Meat", 111 Price: 10, 112 }, 113 } 114 115 mux := http.NewServeMux() 116 mux.Handle("/pizzas", pizzasHandler{&pizzas}) 117 mux.Handle("/orders", ordersHandler{&pizzas, &orders}) 118 119 log.Fatal(http.ListenAndServe(":8080", mux)) 120 }
pizzas 和 orders 數據都保留在記憶體中,為了儘可能簡單,沒有任何數據存儲持久化,如果需要,我可以開設另一篇來講 gorm 之類的,也是現學的 :)
也不檢查請求的header,客戶端發的data body
運行
本地啟動
go run main.go
### https://www.cnblogs.com/wade-xu/p/16705918.html ###
測試
調用 get all pizzas 介面
創建一個 order 訂4個 Veggie pizzas
curl -X POST localhost:8080/orders -d '{"pizza_id":1,"quantity":4}' | jq
再創建一個Order 訂2個 Cheese pizzas
curl -X POST localhost:8080/orders -d '{"pizza_id":2,"quantity":2}' | jq { "pizza_id": 2, "quantity": 2, "total": 22 }
最後 Get orders 看下
Simple HTTP server works well.
### https://www.cnblogs.com/wade-xu/p/16705918.html ###
感謝閱讀,如果您覺得本文的內容對您的學習有所幫助,您可以打賞和推薦,您的鼓勵是我創作的動力。
Learning by Doing