RESTful 是目前最为流行的一种互联网软件结构。由于它结构清晰、符合标准、易于理解、扩展方便,因此正获得愈来愈多网站的采用。html
REST(REpresentational State Transfer),首次出如今 2000 年 Roy Thomas Fielding 的博士论文中,它指的是一组架构约束条件和原则。知足这些约束条件和原则的应用程序或设计就是 RESTful 的。git
综上所述,咱们总结一下什么是 RESTful 架构:github
一、每个 URI 表明一种资源web
二、客户端和服务端之间,传递这种资源的某种表现层json
三、客户端经过四个 HTTP 动词,对服务端资源进行操做,实现“表现层状态转化”bash
将它们概述为图片形式,则 REST 架构图为:服务器
REST 的扩展性:网络
RPC(Remote Procedure Call Protocol)远程过程调用协议,是一种经过网络从远程计算机程序上请求服务,而不须要了解底层网络技术的协议。它假定某些传输协议的存在,如 TCP 或 UDP,以便为通讯程序之间携带信息数据。经过它可使函数调用模式网络化。在 OSI 网络通讯模型中,RPC 跨越了传输层和应用层。RPC 使得开发包括网络分布式多程序在内的应用程序更加容易。架构
运行时,一次客户端对服务器的 RPC 调用,其内部操做大体有以下步骤:app
一、调用客户端句柄;执行传送参数
二、调用本地系统内核发送网络消息
三、消息传送到服务端
四、服务器句柄获得消息并取得参数
五、执行远程过程
六、执行的过程将结果返回服务器句柄
七、服务器句柄返回结果,调用远程系统内核
八、消息传回本地主机
九、客户端句柄由内核接收消息
十、客户端接收句柄返回的数据
在作 API 服务器开发时,不少人都会遇到这个问题 —— 选择 REST 仍是 RPC。RPC 相比 REST 的优势主要有 3 点:
一、RPC+Protobuf 采用的是 TCP 作传输协议,REST 直接使用 HTTP 作应用层协议,这种区别致使 REST 在调用性能上会比 RPC+Protobuf 低
二、RPC 不像 REST 那样,每个操做都要抽象成对资源的增删改查,在实际开发中,有不少操做很难抽象成资源,好比登陆操做。因此在实际开发中并不能严格按照 REST 规范来写 API,RPC 就不存在这个问题
三、RPC 屏蔽网络细节、易用,和本地调用相似
可是 REST 相较 RPC 也有不少优点:
一、轻量级,简单易用,维护性和扩展性都比较好
二、REST 相对更规范,更标准,更通用,不管哪一种语言都支持 HTTP 协议,能够对接外部不少系统,只要知足 HTTP 调用便可,更适合对外,RPC 会有语言限制,不一样语言的 RPC 调用起来很麻烦
三、JSON 格式可读性更强,开发调试都很方便
四、在开发过程当中,若是严格按照 REST 规范来写 API,API 看起来更清晰,更容易被你们理解
其实业界广泛采用的作法是,内部系统之间调用用 RPC,对外用 REST,由于内部系统之间可能调用很频繁,须要 RPC 的高性能支撑。对外用 REST 更易理解,更通用些。
一个 RESTful 服务本质上首先是一个 Web service。下面是一个最简单的 Web server,对于任何请求都简单的直接返回请求连接:
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)) }
编译运行以后,使用 curl 测试,结果以下:
$ curl -v -XGET -H "Content-Type: application/json" http://127.0.0.1:8080/user Hello, "/user"
很显然,咱们的线上项目不可能使用这么简单的 API 服务器。当用户增长,请求也会不断上涨,该如何处理好这些请求?做者使用了一个开源路由框架 mux。这是一个小巧高效,且使用较广的第三方框架。接下来的篇幅里,做者会使用 mux 搭建一个 API 服务器框架。
$go get github.com/gorilla/mux
//Router.go 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 { var handler http.Handler handler = route.HandlerFunc handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler.ServeHTTP(w, r) }) router.Methods(route.Method).Path(route.Pattern).Name(route.Name).Handler(handler) } return router } var routes = Routes{ Route{ "DeleteItem", "DELETE", "/v1/delete", v1_deleteItem, }, ... }
//Handler.go func v1_deleteItem(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(jsonErr{Code: http.StatusOK, Text: "操做成功"}); err != nil { log.print("%s\n%s", err.Error(), debug.Stack()) } }
总体 mux 功能实现:
//main.go func main() { router := NewRouter() log.print("service running(PID:%d)...", os.Getpid()) log.Fatal(http.ListenAndServe(":8080", router)) }
API 基本框架已经实现,接下来就是将相应功能实现模块与相应接口对接便可。
对于想要学习做为一个客户端开发者如何独立完成一个具备 API 服务器功能的线上 APP,能够参考专栏《如何独立开发一个完整应用》,专栏中使用线上 APP 靓手艺 做为案例,详细分享了笔者如何实现 APP 所有功能。