go restful 安全_基于Go语言快速构建一个RESTful API服务

n this post, we will not only cover how to use Go to create a RESTful JSON API, but we will also talk about good RESTful design.

Author:CORY LANOU:a full stack technologist who has specialized in start-ups for the last 17 years. I'm currently working at InfluxDB on their core data team. I also help lead and organizer several community technology meetups and do Go training.

What is a JSON API?

JSON API 是数据交互规范,用以定义客户端如何获取与修改资源,以及服务器如何响应对应请求。JSON API设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。通过遵循共同的约定,可以提高开发效率,利用更普遍的工具,基于 JSON API 的客户端还能够充分利用缓存,以提升性能。(更多:http://jsonapi.org.cn/format/)。

示例:

{

"links": {

"posts.author": {

"href": "http://example.com/people/{posts.author}",

"type": "people"

},

"posts.comments": {

"href": "http://example.com/comments/{posts.comments}",

"type": "comments"

}

},

"posts": [{

"id": "1",

"title": "Rails is Omakase",

"links": {

"author": "9",

"comments": [ "5", "12", "17", "20" ]

}

}]

}

启动一个RESTful服务

$ go run main.go

$ curl http://localhost:8080

Hello,"/"

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

}

增加路径分发功能

路径又称"终点"(endpoint),表示API的具体网址。在RESTful架构中,每个网址代表一种资源(resource)。 第三方组件(Gorilla Mux package): “http://github.com/gorilla/mux”

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)

}

访问测试:

$ curl http://localhost:8080/todo

404 page not found

$ curl http://localhost:8080/todos

Todo Index! ,"/todos"

$ curl http://localhost:8080/todos/{123}

TodoShow: ,"123"

抽象数据模型

创建一个数据模型“Todo”、“Routes”。在其它语言中,使用类(class)实现。 在Go语言中,没有class,必须使用结构(struct)。

Todo.go

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

Routes.go

package main

import (

"net/http"

"github.com/gorilla/mux"

)

type Route struct {

Name string

Method string

Pattern string

HandlerFunc http.HandlerFunc

}

type Routes []Route

重构:Handlers & Router

Handlers.go

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)

}

Router.go

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

}

启动入口是不是清爽很多!

Main.go

Main.go

package main

import (

"log"

"net/http"

)

func main() {

router := NewRouter()

log.Fatal(http.ListenAndServe(":8080", router))

}Todo Index! ,"/todos" [ { "id":0, "name":"Write sth ....", "completed":false, "due":"0001-01-01T00:00:00 }, { "id":1, "name":"Host meetup ....", "completed":false, "due":"0001-01-01T00:00:00Z" } ]

增强功能:持久化

func TodoCreate(w http.ResponseWriter, r *http.Request) {

var todo Todo

//add Todo instance

}

增强功能:日志

2017/05/23 15:57:23 http: multiple response.WriteHeader calls

2017/05/23 15:57:23 GET /todos TodoIndex 6.945807ms

2017/05/23 16:18:40 http: multiple response.WriteHeader calls

2017/05/23 16:18:40 GET /todos TodoIndex 2.127435ms

Things We Didn’t Do版本控制 API版本迭代 & 跨版本资源访问。常用做法是将版本号放在URL,较为简洁,例如:https://localhost:8080/v1/ 另一种做法是将版本号放在HTTP头信息中。

授权验证:涉及到OAuth和JWT。 (1)OAuth 2.0,OAuth2 is an authentication framework,RFC 6749 OAuth2是一种授权框架,提供了一套详细的、可供实践的指导性解决方案。OAuth 2.0定义了四种授权方式。授权码模式(authorization code)、简化模式(implicit)、密码模式(resource owner password credentials)、客户端模式(client credentials)。

(2)JSON web tokens,JWT is an authentication protocol,RFC 7519 JWT是一种安全协议。基本思路就是用户提供用户名和密码给认证服务器,服务器验证用户提交信息信息的合法性;如果验证成功,会产生并返回一个Token(令牌),用户可以使用这个token访问服务器上受保护的资源。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

header:定义算法(alg:ALGORITHM)和TOKEN TYPE(typ)

{

"alg": "HS256",

"typ": "JWT"

}

Data:

{

"sub": "1234567890",

"name": "John Doe",

"admin": true

}eTags:关于缓存、性能和用户标识和追踪。

参考文献阮一峰:RESTful API 设计指南CORY LANOU:Making a RESTful JSON API in Go,2014NovInfoQ:使用ETags减少Web应用带宽和负载Stackoverflow:jwt vs oauth authenticationOAuth 2 VS JSON Web Tokens:How to secure an API,20160605阮一峰:理解OAuth 2.0,201405

更多精彩内容,请扫码关注公众号:@睿哥杂货铺 RSS订阅:Ribose Yim's Blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值