云原生之旅 - 1)Golang 入门 简单 HTTP Server

前言

本人最近几年一直在学习并且实践云原生,也从测试转型到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 如下:

  1. Get 请求 -  List all pizzas: /pizzas
  2. POST 请求 - Make a pizza order: /orders
  3. 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

Source code

 

运行

本地启动 

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 ###

 

感谢阅读,如果您觉得本文的内容对您的学习有所帮助,您可以打赏和推荐,您的鼓励是我创作的动力。

 

posted @ 2022-09-19 21:06  WadeXu  阅读(1438)  评论(0编辑  收藏  举报