一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術(shù)及教程分享平臺(tái)!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Golang - 詳解Go語言RESTful JSON API創(chuàng)建

詳解Go語言RESTful JSON API創(chuàng)建

2020-05-15 10:20WalkerQiao Golang

這篇文章主要介紹了詳解Go語言RESTful JSON API創(chuàng)建,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

RESTful API在Web項(xiàng)目開發(fā)中廣泛使用,本文針對(duì)Go語言如何一步步實(shí)現(xiàn)RESTful JSON API進(jìn)行講解, 另外也會(huì)涉及到RESTful設(shè)計(jì)方面的話題。

也許我們之前有使用過各種各樣的API, 當(dāng)我們遇到設(shè)計(jì)很糟糕的API的時(shí)候,簡(jiǎn)直感覺崩潰至極。希望通過本文之后,能對(duì)設(shè)計(jì)良好的RESTful API有一個(gè)初步認(rèn)識(shí)。

JSON API是什么?

JSON之前,很多網(wǎng)站都通過XML進(jìn)行數(shù)據(jù)交換。如果在使用過XML之后,再接觸JSON, 毫無疑問,你會(huì)覺得世界多么美好。這里不深入JSON API的介紹,有興趣可以參考jsonapi

基本的Web服務(wù)器

從根本上講,RESTful服務(wù)首先是Web服務(wù)。 因此我們可以先看看Go語言中基本的Web服務(wù)器是如何實(shí)現(xiàn)的。下面例子實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的Web服務(wù)器,對(duì)于任何請(qǐng)求,服務(wù)器都響應(yīng)請(qǐng)求的URL回去。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
 
import (
  "fmt"
  "html"
  "log"
  "net/http"
)
 
func main() {
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
  })
 
  log.Fatal(http.ListenAndServe(":8080", nil))
}

上面基本的web服務(wù)器使用Go標(biāo)準(zhǔn)庫的兩個(gè)基本函數(shù)HandleFunc和ListenAndServe。

?
1
2
3
4
5
6
7
8
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
  DefaultServeMux.HandleFunc(pattern, handler)
}
 
func ListenAndServe(addr string, handler Handler) error {
  server := &Server{Addr: addr, Handler: handler}
  return server.ListenAndServe()
}

運(yùn)行上面的基本web服務(wù),就可以直接通過瀏覽器訪問http://localhost:8080來訪問。

?
1
> go run basic_server.go

添加路由

雖然標(biāo)準(zhǔn)庫包含有router, 但是我發(fā)現(xiàn)很多人對(duì)它的工作原理感覺很困惑。 我在自己的項(xiàng)目中使用過各種不同的第三方router庫。 最值得一提的是Gorilla Web ToolKit的mux router。

另外一個(gè)流行的router是來自Julien Schmidt的叫做httprouter的包。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
 
import (
  "fmt"
  "html"
  "log"
  "net/http"
 
  "github.com/gorilla/mux"
)
 
func main() {
  router := mux.NewRouter().StrictSlash(true)
  router.HandleFunc("/", Index)
 
  log.Fatal(http.ListenAndServe(":8080", router))
}
 
func Index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}

要運(yùn)行上面的代碼,首先使用go get獲取mux router的源代碼:

?
1
> go get github.com/gorilla/mux

上面代碼創(chuàng)建了一個(gè)基本的路由器,給請(qǐng)求"/"賦予Index處理器,當(dāng)客戶端請(qǐng)求http://localhost:8080/的時(shí)候,就會(huì)執(zhí)行Index處理器。

如果你足夠細(xì)心,你會(huì)發(fā)現(xiàn)之前的基本web服務(wù)訪問http://localhost:8080/abc能正常響應(yīng): 'Hello, "/abc"', 但是在添加了路由之后,就只能訪問http://localhost:8080了。 原因很簡(jiǎn)單,因?yàn)槲覀冎惶砑恿藢?duì)"/"的解析,其他的路由都是無效路由,因此都是404。

創(chuàng)建一些基本的路由

既然我們加入了路由,那么我們就可以再添加更多路由進(jìn)來了。

假設(shè)我們要?jiǎng)?chuàng)建一個(gè)基本的ToDo應(yīng)用, 于是我們的代碼就變成下面這樣:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main
 
import (
  "fmt"
  "log"
  "net/http"
 
  "github.com/gorilla/mux"
)
 
func main() {
  router := mux.NewRouter().StrictSlash(true)
  router.HandleFunc("/", Index)
  router.HandleFunc("/todos", TodoIndex)
  router.HandleFunc("/todos/{todoId}", TodoShow)
 
  log.Fatal(http.ListenAndServe(":8080", router))
}
 
func Index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Welcome!")
}
 
func TodoIndex(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Todo Index!")
}
 
func TodoShow(w http.ResponseWriter, r *http.Request) {
  vars := mux.Vars(r)
  todoId := vars["todoId"]
  fmt.Fprintln(w, "Todo Show:", todoId)
}

在這里我們添加了另外兩個(gè)路由: todos和todos/{todoId}。

這就是RESTful API設(shè)計(jì)的開始。

請(qǐng)注意最后一個(gè)路由我們給路由后面添加了一個(gè)變量叫做todoId。

這樣就允許我們傳遞id給路由,并且能使用具體的記錄來響應(yīng)請(qǐng)求。

基本模型

路由現(xiàn)在已經(jīng)就緒,是時(shí)候創(chuàng)建Model了,可以用model發(fā)送和檢索數(shù)據(jù)。在Go語言中,model可以使用結(jié)構(gòu)體來實(shí)現(xiàn),而其他語言中model一般都是使用類來實(shí)現(xiàn)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
 
import (
  "time"
)
 
type Todo struct {
  Name   string
  Completed bool
  Due    time.Time
}
 
type Todos []Todo

上面我們定義了一個(gè)Todo結(jié)構(gòu)體,用于表示待做項(xiàng)。 另外我們還定義了一種類型Todos, 它表示待做列表,是一個(gè)數(shù)組,或者說是一個(gè)分片。

稍后你就會(huì)看到這樣會(huì)變得非常有用。

返回一些JSON

我們有了基本的模型,那么我們可以模擬一些真實(shí)的響應(yīng)了。我們可以為TodoIndex模擬一些靜態(tài)的數(shù)據(jù)列表。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main
 
import (
  "encoding/json"
  "fmt"
  "log"
  "net/http"
 
  "github.com/gorilla/mux"
)
 
// ...
 
func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }
 
  json.NewEncoder(w).Encode(todos)
}
 
// ...

現(xiàn)在我們創(chuàng)建了一個(gè)靜態(tài)的Todos分片來響應(yīng)客戶端請(qǐng)求。注意,如果你請(qǐng)求http://localhost:8080/todos, 就會(huì)得到下面的響應(yīng):

?
1
2
3
4
5
6
7
8
9
10
11
12
[
  {
    "Name": "Write presentation",
    "Completed": false,
    "Due": "0001-01-01T00:00:00Z"
  },
  {
    "Name": "Host meetup",
    "Completed": false,
    "Due": "0001-01-01T00:00:00Z"
  }
]

更好的Model

對(duì)于經(jīng)驗(yàn)豐富的老兵來說,你可能已經(jīng)發(fā)現(xiàn)了一個(gè)問題。響應(yīng)JSON的每個(gè)key都是首字母答寫的,雖然看起來微不足道,但是響應(yīng)JSON的key首字母大寫不是習(xí)慣的做法。 那么下面教你如何解決這個(gè)問題:

?
1
2
3
4
5
type Todo struct {
  Name   string  `json:"name"`
  Completed bool   `json:"completed"`
  Due    time.Time `json:"due"`
}

其實(shí)很簡(jiǎn)單,就是在結(jié)構(gòu)體中添加標(biāo)簽屬性, 這樣可以完全控制結(jié)構(gòu)體如何編排(marshalled)成JSON。

拆分代碼

到目前為止,我們所有代碼都在一個(gè)文件中。顯得雜亂, 是時(shí)候拆分代碼了。我們可以將代碼按照功能拆分成下面多個(gè)文件。

我們準(zhǔn)備創(chuàng)建下面的文件,然后將相應(yīng)代碼移到具體的代碼文件中:

  1. main.go: 程序入口文件。
  2. handlers.go: 路由相關(guān)的處理器。
  3. routes.go: 路由。
  4. todo.go: todo相關(guān)的代碼。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main
 
import (
  "encoding/json"
  "fmt"
  "net/http"
 
  "github.com/gorilla/mux"
)
 
func Index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Welcome!")
}
 
func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }
 
  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}
 
func TodoShow(w http.ResponseWriter, r *http.Request) {
  vars := mux.Vars(r)
  todoId := vars["todoId"]
  fmt.Fprintln(w, "Todo show:", todoId)
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main
 
import (
  "net/http"
 
  "github.com/gorilla/mux"
)
 
type Route struct {
  Name    string
  Method   string
  Pattern   string
  HandlerFunc http.HandlerFunc
}
 
type Routes []Route
 
func NewRouter() *mux.Router {
 
  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(route.HandlerFunc)
  }
 
  return router
}
 
var routes = Routes{
  Route{
    "Index",
    "GET",
    "/",
    Index,
  },
  Route{
    "TodoIndex",
    "GET",
    "/todos",
    TodoIndex,
  },
  Route{
    "TodoShow",
    "GET",
    "/todos/{todoId}",
    TodoShow,
  },
}
?
1
2
3
4
5
6
7
8
9
10
11
package main
 
import "time"
 
type Todo struct {
  Name   string  `json:"name"`
  Completed bool   `json:"completed"`
  Due    time.Time `json:"due"`
}
 
type Todos []Todo
?
1
2
3
4
5
6
7
8
9
10
package main
import (
  "log"
  "net/http"
)
 
func main() {
  router := NewRouter()
  log.Fatal(http.ListenAndServe(":8080", router))
}

更好的Routing

我們重構(gòu)的過程中,我們創(chuàng)建了一個(gè)更多功能的routes文件。 這個(gè)新文件利用了一個(gè)包含多個(gè)關(guān)于路由信息的結(jié)構(gòu)體。 注意,這里我們可以指定請(qǐng)求的類型,例如GET, POST, DELETE等等。

輸出Web日志

在拆分的路由文件中,我也包含有一個(gè)不可告人的動(dòng)機(jī)。稍后你就會(huì)看到,拆分之后很容易使用另外的函數(shù)來修飾http處理器。

首先我們需要有對(duì)web請(qǐng)求打日志的能力,就像很多流行web服務(wù)器那樣的。 在Go語言中,標(biāo)準(zhǔn)庫里邊沒有web日志包或功能, 因此我們需要自己創(chuàng)建。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package logger
import (
  "log"
  "net/http"
  "time"
)
 
func Logger(inner http.Handler, name string) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    start := time.Now()
    inner.ServeHTTP(w, r)
    log.Printf(
      "%s\t%s\t%s\t%s",
      r.Method,
      r.RequestURI,
      name,
      time.Since(start),
    )
  })
}

上面我們定義了一個(gè)Logger函數(shù),可以給handler進(jìn)行包裝修飾。

這是Go語言中非常標(biāo)準(zhǔn)的慣用方式。其實(shí)也是函數(shù)式編程的慣用方式。 非常有效,我們只需要將Handler傳入該函數(shù), 然后它會(huì)將傳入的handler包裝一下,添加web日志和耗時(shí)統(tǒng)計(jì)功能。

應(yīng)用Logger修飾器

要應(yīng)用Logger修飾符, 我們可以創(chuàng)建router, 我們只需要簡(jiǎn)單的將我們所有的當(dāng)前路由都包到其中, NewRouter函數(shù)修改如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func NewRouter() *mux.Router {
 
  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    var handler http.Handler
 
    handler = route.HandlerFunc
    handler = Logger(handler, route.Name)
 
    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(handler)
  }
 
  return router
}

現(xiàn)在再次運(yùn)行我們的程序,我們就可以看到日志大概如下:

2014/11/19 12:41:39 GET /todos TodoIndex 148.324us

這個(gè)路由文件太瘋狂...讓我們重構(gòu)它吧

路由routes文件現(xiàn)在已經(jīng)變得稍微大了些, 下面我們將它分解成多個(gè)文件:

  1. routes.go
  2. router.go
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main
 
import "net/http"
 
type Route struct {
  Name    string
  Method   string
  Pattern   string
  HandlerFunc http.HandlerFunc
}
 
type Routes []Route
 
var routes = Routes{
  Route{
    "Index",
    "GET",
    "/",
    Index,
  },
  Route{
    "TodoIndex",
    "GET",
    "/todos",
    TodoIndex,
  },
  Route{
    "TodoShow",
    "GET",
    "/todos/{todoId}",
    TodoShow,
  },
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
 
import (
  "net/http"
 
  "github.com/gorilla/mux"
)
 
func NewRouter() *mux.Router {
  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    var handler http.Handler
    handler = route.HandlerFunc
    handler = Logger(handler, route.Name)
 
    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(handler)
 
  }
  return router
}

另外再承擔(dān)一些責(zé)任

到目前為止,我們已經(jīng)有了一些相當(dāng)好的樣板代碼(boilerplate), 是時(shí)候重新審視我們的處理器了。我們需要稍微多的責(zé)任。 首先修改TodoIndex,添加下面兩行代碼:

?
1
2
3
4
5
6
7
8
9
10
11
func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusOK)
  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}

這里發(fā)生了兩件事。 首先,我們?cè)O(shè)置了響應(yīng)類型并告訴客戶端期望接受JSON。第二,我們明確的設(shè)置了響應(yīng)狀態(tài)碼。

Go語言的net/http服務(wù)器會(huì)嘗試為我們猜測(cè)輸出內(nèi)容類型(然而并不是每次都準(zhǔn)確的), 但是既然我們已經(jīng)確切的知道響應(yīng)類型,我們總是應(yīng)該自己設(shè)置它。

稍等片刻,我們的數(shù)據(jù)庫在哪里?

很明顯,如果我們要?jiǎng)?chuàng)建RESTful API, 我們需要一些用于存儲(chǔ)和檢索數(shù)據(jù)的地方。然而,這個(gè)是不是本文的范圍之內(nèi), 因此我們將簡(jiǎn)單的創(chuàng)建一個(gè)非常簡(jiǎn)陋的模擬數(shù)據(jù)庫(非線程安全的)。

我們創(chuàng)建一個(gè)repo.go文件,內(nèi)容如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main
 
import "fmt"
 
var currentId int
 
var todos Todos
 
// Give us some seed data
func init() {
  RepoCreateTodo(Todo{Name: "Write presentation"})
  RepoCreateTodo(Todo{Name: "Host meetup"})
}
 
func RepoFindTodo(id int) Todo {
  for _, t := range todos {
    if t.Id == id {
      return t
    }
  }
  // return empty Todo if not found
  return Todo{}
}
 
func RepoCreateTodo(t Todo) Todo {
  currentId += 1
  t.Id = currentId
  todos = append(todos, t)
  return t
}
func RepoDestroyTodo(id int) error {
  for i, t := range todos {
    if t.Id == id {
      todos = append(todos[:i], todos[i+1:]...)
      return nil
    }
  }
  return fmt.Errorf("Could not find Todo with id of %d to delete", id)
}

給Todo添加ID

我們創(chuàng)建了模擬數(shù)據(jù)庫,我們使用并賦予id, 因此我們相應(yīng)的也需要更新我們的Todo結(jié)構(gòu)體。

?
1
2
3
4
5
6
7
8
9
package main
import "time"
type Todo struct {
  Id    int    `json:"id"`
  Name   string  `json:"name"`
  Completed bool   `json:"completed"`
  Due    time.Time `json:"due"`
}
type Todos []Todo

更新我們的TodoIndex

要使用數(shù)據(jù)庫,我們需要在TodoIndex中檢索數(shù)據(jù)。修改代碼如下:

?
1
2
3
4
5
6
7
func TodoIndex(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusOK)
  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}

POST JSON

到目前為止,我們只是輸出JSON, 現(xiàn)在是時(shí)候進(jìn)入存儲(chǔ)一些JSON了。

在routes.go文件中添加如下路由:

?
1
2
3
4
5
6
Route{
  "TodoCreate",
  "POST",
  "/todos",
  TodoCreate,
},

Create路由

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func TodoCreate(w http.ResponseWriter, r *http.Request) {
  var todo Todo
  body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
  if err != nil {
    panic(err)
  }
  if err := r.Body.Close(); err != nil {
    panic(err)
  }
  if err := json.Unmarshal(body, &todo); err != nil {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.WriteHeader(422) // unprocessable entity
    if err := json.NewEncoder(w).Encode(err); err != nil {
      panic(err)
    }
  }
 
  t := RepoCreateTodo(todo)
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusCreated)
  if err := json.NewEncoder(w).Encode(t); err != nil {
    panic(err)
  }
}

首先我們打開請(qǐng)求的body。 注意我們使用io.LimitReader。這樣是保護(hù)服務(wù)器免受惡意攻擊的好方法。假設(shè)如果有人想要給你服務(wù)器發(fā)送500GB的JSON怎么辦?

我們讀取body以后,我們解構(gòu)Todo結(jié)構(gòu)體。 如果失敗,我們作出正確的響應(yīng),使用恰當(dāng)?shù)捻憫?yīng)碼422, 但是我們依然使用json響應(yīng)回去。 這樣可以允許客戶端理解有錯(cuò)發(fā)生了, 而且有辦法知道到底發(fā)生了什么錯(cuò)誤。

最后,如果所有都通過了,我們就響應(yīng)201狀態(tài)碼,表示請(qǐng)求創(chuàng)建的實(shí)體已經(jīng)成功創(chuàng)建了。 我們同樣還是響應(yīng)回代表我們創(chuàng)建的實(shí)體的json, 它會(huì)包含一個(gè)id, 客戶端可能接下來需要用到它。

POST一些JSON

我們現(xiàn)在有了偽repo, 也有了create路由,那么我們需要post一些數(shù)據(jù)。 我們使用curl通過下面的命令來達(dá)到這個(gè)目的:

 

復(fù)制代碼 代碼如下:
curl -H "Content-Type: application/json" -d '{"name": "New Todo"}' http://localhost:8080/todos

 

如果你再次通過http://localhost:8080/todos訪問,大概會(huì)得到下面的響應(yīng):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
  {
    "id": 1,
    "name": "Write presentation",
    "completed": false,
    "due": "0001-01-01T00:00:00Z"
  },
  {
    "id": 2,
    "name": "Host meetup",
    "completed": false,
    "due": "0001-01-01T00:00:00Z"
  },
  {
    "id": 3,
    "name": "New Todo",
    "completed": false,
    "due": "0001-01-01T00:00:00Z"
  }
]

我們還沒有做的事情

雖然我們已經(jīng)有了很好的開端,但是還有很多事情沒有做:

  1. 版本控制: 如果我們需要修改API, 結(jié)果完全改變了怎么辦? 可能我們需要在我們的路由開頭加上/v1/prefix?
  2. 授權(quán): 除非這些都是公開/免費(fèi)API, 我們可能還需要授權(quán)。 建議學(xué)習(xí)JSON web tokens的東西。

eTag - 如果你正在構(gòu)建一些需要擴(kuò)展的東西,你可能需要實(shí)現(xiàn)eTag。

還有什么?

對(duì)于所有項(xiàng)目來說,開始都很小,但是很快就變得失控了。但是如果我們想要將它帶到另外一個(gè)層次, 讓他生產(chǎn)就緒, 還有一些額外的事情需要做:

  1. 大量重構(gòu)(refactoring).
  2. 為這些文件創(chuàng)建幾個(gè)包,例如一些JSON助手、修飾符、處理器等等。
  3. 測(cè)試, 使得,你不能忘記這點(diǎn)。這里我們沒有做任何測(cè)試。對(duì)于生產(chǎn)系統(tǒng)來說,測(cè)試是必須的。

源代碼:https://github.com/corylanou/tns-restful-json-api

總結(jié)

對(duì)我來說,最重要的,需要記住的是我們要建立一個(gè)負(fù)責(zé)任的API。 發(fā)送適當(dāng)?shù)臓顟B(tài)碼,header等,這些是API廣泛采用的關(guān)鍵。我希望本文能讓你盡快開始自己的API。

參考鏈接

Go語言RESTful JSON API實(shí)現(xiàn)
JSON API
Gorilla Web Toolkit
httprouter
JSON Web Tokens
eTag

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://segmentfault.com/a/1190000014875956

延伸 · 閱讀

精彩推薦
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • Golanggolang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • GolangGolang通脈之?dāng)?shù)據(jù)類型詳情

    Golang通脈之?dāng)?shù)據(jù)類型詳情

    這篇文章主要介紹了Golang通脈之?dāng)?shù)據(jù)類型,在編程語言中標(biāo)識(shí)符就是定義的具有某種意義的詞,比如變量名、常量名、函數(shù)名等等,Go語言中標(biāo)識(shí)符允許由...

    4272021-11-24
  • Golanggolang的httpserver優(yōu)雅重啟方法詳解

    golang的httpserver優(yōu)雅重啟方法詳解

    這篇文章主要給大家介紹了關(guān)于golang的httpserver優(yōu)雅重啟的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,...

    helight2992020-05-14
  • Golanggo日志系統(tǒng)logrus顯示文件和行號(hào)的操作

    go日志系統(tǒng)logrus顯示文件和行號(hào)的操作

    這篇文章主要介紹了go日志系統(tǒng)logrus顯示文件和行號(hào)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang如何使用struct的tag屬性的詳細(xì)介紹

    golang如何使用struct的tag屬性的詳細(xì)介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細(xì)介紹,從例子說起,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看...

    Go語言中文網(wǎng)11352020-05-21
  • GolangGolang中Bit數(shù)組的實(shí)現(xiàn)方式

    Golang中Bit數(shù)組的實(shí)現(xiàn)方式

    這篇文章主要介紹了Golang中Bit數(shù)組的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧...

    天易獨(dú)尊11682021-06-09
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
主站蜘蛛池模板: 欧美xxoo黑人又粗暴 | 无限在线观看视频大全免费高清 | 国产特级毛片aaaaaa | 四虎影院在线免费观看 | 色哟约 | 视频免费观看在线播放高清 | 91制片厂制作果冻传媒123 | 国产三级精品久久三级国专区 | 驯服有夫之妇HD中字日本 | 九九艹 | 狠狠色综合久久婷婷 | 娇妻被老外疯狂调教 | 国产精品自产拍在线观看2019 | 午夜成私人影院在线观看 | 我们中文在线观看免费完整版 | 嫩草视频在线观看视频播放 | 亚洲第一区se | 美日韩在线观看 | 三级伦理在线播放 | 逼逼爱 | 日本肉体xxxx | 99年水嫩漂亮粉嫩在线播放 | 夫妻性生活免费在线观看 | 岛国a香蕉片不卡在线观看 荡女淫春2古装 | 久久视频这里只精品99热在线观看 | 免费国产一级 | 99av麻豆| 黑人巨大初黑人解禁作品 | 国产成+人+综合+欧美 亚洲 | 国自产在线精品免费 | 国产一级片免费视频 | 亚洲欧美久久一区二区 | 97热久久免费频精品99国产成人 | 亚洲国产精品线在线观看 | 日本一区二区视频在线观看 | 亚洲国产视频网站 | 天天狠天天天天透在线 | 国产 日韩欧美 | 亚洲精品国产在线网站 | 国产在线看片网站 | xxoosex久久久久久 |