golang 实现一个restful微服务的操作
来源:脚本之家
时间:2023-01-07 11:58:35 220浏览 收藏
怎么入门Golang编程?需要学习哪些知识点?这是新手们刚接触编程时常见的问题;下面golang学习网就来给大家整理分享一些知识点,希望能够给初学者一些帮助。本篇文章就来介绍《golang 实现一个restful微服务的操作》,涉及到微服务、RESTful,有需要的可以收藏一下
如何用net/http构建一个简单的web服务
Golang提供了简洁的方法来构建web服务
1 2 3 4 5 6 7 8 9 10 11 12 13 | package main import ( "net/http" ) func HelloResponse(rw http.ResponseWriter, request *http.Request) { fmt.Fprintf(w, "Hello world.") } func main() { http.HandleFunc("/", HelloResponse) http.ListenAndServe(":3000", nil) } |
其中核心的两个方法:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)):HandleFunc注册一个handler function对应到给定的pattern。
func ListenAndServe(addr string, handler Handler) error:ListenAndServe监听给定的TCP网络地址,接着带上handler调用Serve方法来接收请求。
在go build之后,执行编译后的文件就能在客户端看到hello world了
有了web服务,就可以制定小目标了
我认为作为第一版本,不需要复杂的设计,只需要接收到用户的请求,并且找到对应的handler,执行其逻辑,然后返回JSON响应就好了。
小目标有了,那怎么实现呢?
1.设计用户如何注册Controller和Action
据我观察,一些框架是在Controller里预先设定了GET,POST,PUT等一系列方法,负责接收GET,POST,PUT的HTTP请求。
我认为这样设计的确有其优势,因为用户只需要实现这些方法就好了,但在业务层面也有其劣势,因为我们没有办法保证负责一个页面或者功能的Controller只接收一个GET请求,如果有2个GET请求,那就需要再建立一个Controller,单单实现其GET方法。
因此我借鉴了PHP社区中Laravel注册Controller和Action的语法:Get("/", "IndexController@Index")。
用户只需要定义:
1 2 3 4 5 | type IndexController struct { } func (IndexController *IndexController) Index(//params) (//return values) { } |
当然这样思考后,就给框架带入了一点动态脚本语言的特性,肯定会用到Golang的reflect库。
2.设计Path和Controller还有Action的关系容器
我运用了Golang的map,定义了map[string]map[string]map[string]string这样的数据结构
以["/":["GET":["IndexController":"Get"], "POST":["IndexController":"Post"]], "/foo":["GET":["IndexController":"Foo"]]]举例:
这个说明了在"/"这个PATH下面,有GET和POST请求,分别对应了IndexController下的Get和Post方法,在"/foo"这个PATH下面,有GET请求,对应IndexController下的Foo方法。
在接受请求时候,如果没有找到对应的方法,就返回405。
3.如何将注册了的一系列Method与PATH绑定来接收外部请求
我们可以看到,func HandleFunc(pattern string, handler func(ResponseWriter, *Request))要求的handler类型是func(ResponseWriter, *Request)),这和我们设计的functionfunc (IndexController *IndexController) Index(//params) (//return values) {}有所差距。
这时候我发现由于Golang具备First Class Functions特性,因此我们可以将函数做如下处理:
1 2 3 4 5 6 | http.HandleFunc(path, HandleRequest()) func HandleRequest() { return func(rw http.ResponseWriter, request *http.Request) { // do your logic } } |
4.和encoding/json说Hi
当我们接收到function的返回值后,我们就需要对结果进行json encode,而encoding/json正是负责这个功能。 我用的是json.Marshal():
func Marshal(v interface{}) ([]byte, error): Marshal返回v的encoding结果。
如何使用
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 ( "net/url" "net/http" "github.com/ZhenhangTung/GoGym" ) type IndexController struct { } func (IndexController *IndexController) Index(request map[string]url.Values, headers http.Header) (statusCode int, response interface{}) { return 200, map[string]string{"hello": "world"} } type BarController struct { } func (*BarController) Bar(request map[string]url.Values, headers http.Header) (statusCode int, response interface{}, responseHeader http.Header) { return 200, map[string]string{"GoTo": "Bar"}, http.Header{"Foo": {"Bar", "Baz"}} } func main() { var apiService = GoGym.Prepare() apiService.Get("index", "IndexController@Index") apiService.Post("bar", "BarController@Bar") controllers := []interface{}{&IndexController{}} apiService.RegisterControllers(controllers) apiService.RegisterController(&BarController{}) apiService.Serve(3000) } |
项目完整代码
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | package GoGym import ( "encoding/json" "fmt" "net/http" "net/url" "reflect" "strings" ) const ( GETMethod = "GET" POSTMethod = "POST" PUTMethod = "PUT" PATCHMethod = "PATCH" DELETEMethod = "DELETE" OPTIONSMethod = "OPTIONS" ) const ( HTTPMethodNotAllowed = 405 ) // APIService for now is the struct for containing controllerRegistry and registeredPathAndController, // and it is the core service provider type APIService struct { // controllerRegistry is where all registered controllers exist controllerRegistry map[string]interface{} //registeredPathAndController is a mapping of paths and controllers registeredPathAndController map[string]map[string]map[string]string requestForm map[string]url.Values } func (api *APIService) Get(path, controllerWithActionString string) { mapping := api.mappingRequestMethodWithControllerAndActions(GETMethod, path, controllerWithActionString) api.registeredPathAndController[path] = mapping } func (api *APIService) Post(path, controllerWithActionString string) { mapping := api.mappingRequestMethodWithControllerAndActions(POSTMethod, path, controllerWithActionString) api.registeredPathAndController[path] = mapping } func (api *APIService) Put(path, controllerWithActionString string) { mapping := api.mappingRequestMethodWithControllerAndActions(PUTMethod, path, controllerWithActionString) api.registeredPathAndController[path] = mapping } func (api *APIService) Patch(path, controllerWithActionString string) { mapping := api.mappingRequestMethodWithControllerAndActions(PATCHMethod, path, controllerWithActionString) api.registeredPathAndController[path] = mapping } func (api *APIService) Options(path, controllerWithActionString string) { mapping := api.mappingRequestMethodWithControllerAndActions(OPTIONSMethod, path, controllerWithActionString) api.registeredPathAndController[path] = mapping } func (api *APIService) Delete(path, controllerWithActionString string) { mapping := api.mappingRequestMethodWithControllerAndActions(DELETEMethod, path, controllerWithActionString) api.registeredPathAndController[path] = mapping } // mappingRequestMethodWithControllerAndActions is a function for mapping request method with controllers // which containing actions func (api *APIService) mappingRequestMethodWithControllerAndActions(requestMethod, path, controllerWithActionString string) map[string]map[string]string { mappingResult := make(map[string]map[string]string) if length := len(api.registeredPathAndController[path]); length > 0 { mappingResult = api.registeredPathAndController[path] } controllerAndActionSlice := strings.Split(controllerWithActionString, "@") controller := controllerAndActionSlice[0] action := controllerAndActionSlice[1] controllerAndActionMap := map[string]string{controller: action} mappingResult[requestMethod] = controllerAndActionMap return mappingResult } // HandleRequest is a function to handle http request func (api *APIService) HandleRequest(controllers map[string]map[string]string) http.HandlerFunc { return func(rw http.ResponseWriter, request *http.Request) { request.ParseForm() method := request.Method api.requestForm["query"] = request.Form api.requestForm["form"] = request.PostForm macthedControllers, ok := controllers[method] if !ok { rw.WriteHeader(HTTPMethodNotAllowed) } for k, v := range macthedControllers { controllerKey := "*" + k controller := api.controllerRegistry[controllerKey] in := make([]reflect.Value, 2) in[0] = reflect.ValueOf(api.requestForm) in[1] = reflect.ValueOf(request.Header) returnValues := reflect.ValueOf(controller).MethodByName(v).Call(in) statusCode := returnValues[0].Interface() intStatusCode := statusCode.(int) response := returnValues[1].Interface() responseHeaders := http.Header{} if len(returnValues) == 3 { responseHeaders = returnValues[2].Interface().(http.Header) } api.JSONResponse(rw, intStatusCode, response, responseHeaders) } } } // RegisterHandleFunc is a function registers a handle function to handle request from path func (api *APIService) RegisterHandleFunc() { for k, v := range api.registeredPathAndController { path := k if !strings.HasPrefix(k, "/") { path = fmt.Sprintf("/%v", k) } http.HandleFunc(path, api.HandleRequest(v)) } } // RegisterControllers is a function registers a struct of controllers into controllerRegistry func (api *APIService) RegisterControllers(controllers []interface{}) { for _, v := range controllers { api.RegisterController(v) } } // RegisterControllers is a function registers a controller into controllerRegistry func (api *APIService) RegisterController(controller interface{}) { controllerType := getType(controller) api.controllerRegistry[controllerType] = controller } // getType is a function gets the type of value func getType(value interface{}) string { if t := reflect.TypeOf(value); t.Kind() == reflect.Ptr { return "*" + t.Elem().Name() } else { return t.Name() } } // Serve is a function func (api *APIService) Serve(port int) { api.RegisterHandleFunc() fullPort := fmt.Sprintf(":%d", port) http.ListenAndServe(fullPort, nil) } // JSONResponse is a function return json response func (api *APIService) JSONResponse(rw http.ResponseWriter, statusCode int, response interface{}, headers http.Header) { for k, v := range headers { for _, header := range v { rw.Header().Add(k, header) } } rw.Header().Add("Content-Type", "application/json") rw.WriteHeader(statusCode) rsp, err := json.Marshal(response) if err != nil { // TODO: logging error fmt.Println("JSON err:", err) } rw.Write(rsp) } // Prepare is a fucntion prepare the service and return prepared service to the user func Prepare() *APIService { var apiService = new(APIService) apiService.controllerRegistry = make(map[string]interface{}) apiService.registeredPathAndController = make(map[string]map[string]map[string]string) apiService.requestForm = make(map[string]url.Values) return apiService } |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。
今天关于《golang 实现一个restful微服务的操作》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于golang的内容请关注golang学习网公众号!
-
354 收藏
-
194 收藏
-
314 收藏
-
462 收藏
-
207 收藏
-
261 收藏
-
460 收藏
-
119 收藏
-
381 收藏
-
362 收藏
-
255 收藏
-
332 收藏
-
239 收藏
-
402 收藏
-
119 收藏
-
180 收藏
-
230 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习