Go Web:RESTful web service示例
restful架构的简介
web服务的架构模式主要有2种:soap和rest。soap和rest都回答了同一个问题:如何访问web服务。
soap风格的程序是功能驱动的,要借助xml来传递数据,明确表示要做什么动作,访问什么资源,但使用xml是非常繁琐复杂的事情。
restful风格的web服务是资源驱动的,通过资源(名词)和http方法get/post/delete/put来实现增删改查的逻辑,偶尔也用patch/head方法。注意,post不是幂等的,而put是幂等的,所以put常用来更新资源,post常用来创建资源。
关于restful风格的web服务,重点体现在uri上。restful风格的web服务的uri不能包含动词,而是只包含名词(资源)。动词或其它相关的意思可以通过http request的header/body或者通过url的query来传递。
例如:
1.获取id=1的文章:/posts/show/1,其中show是动词,这个uri就设计错了,正确的写法应该是/posts/1,然后用get方法表示获取,即show
2.用户1转账500给2:post /accounts/1/transfer/500/to/2
,transfer是动词,是错误的,应该设计成名词,并将动词逻辑相关的参数通过url的query或者请求报文传递
post /transaction http/1.1 host: 127.0.0.1 from=1&to=2&amount=500.00
关于restful的web,参见阮一峰的两篇文章:
restful风格的web服务示例
本示例是描述如何操作博客文章的web服务,对于restful的规范来说,功能并不完善,但对于理解restful来说足够了。
两个源码文件server.go和data.go位于同个目录下,都属于main包,server.go是运行入口,data.go是数据操作逻辑的代码。
以下是server.go文件内容,定义handler。注意处理资源的方式,这是restful风格的web服务核心:uri中不能包含动词,只通过资源来完成动作逻辑。
package main import ( "encoding/json" "net/http" "path" "strconv" ) func main() { server := http.server{ addr: "127.0.0.1:8080", } http.handlefunc("/posts/", handlerequest) server.listenandserve() } func handlerequest(w http.responsewriter, r *http.request) { var err error switch r.method { case "get": err = handleget(w, r) case "post": err = handlepost(w, r) case "put": err = handleput(w, r) case "delete": err = handledelete(w, r) } if err != nil { http.error(w, err.error(), http.statusinternalservererror) return } } func handleget(w http.responsewriter, r *http.request) (err error) { id, err := strconv.atoi(path.base(r.url.path)) if err != nil { return } post, err := retrieve(id) if err != nil { return } output, err := json.marshalindent(&post, "", "\t\t") if err != nil { return } w.header().set("content-type", "application/json") w.write(output) return } func handlepost(w http.responsewriter, r *http.request) (err error) { len := r.contentlength body := make([]byte, len) r.body.read(body) var post post json.unmarshal(body, &post) err = post.create() if err != nil { return } w.writeheader(200) return } func handleput(w http.responsewriter, r *http.request) (err error) { id, err := strconv.atoi(path.base(r.url.path)) if err != nil { return } post, err := retrieve(id) if err != nil { return } len := r.contentlength body := make([]byte, len) r.body.read(body) json.unmarshal(body, &post) err = post.update() if err != nil { return } w.writeheader(200) return } func handledelete(w http.responsewriter, r *http.request) (err error) { id, err := strconv.atoi(path.base(r.url.path)) if err != nil { return } post, err := retrieve(id) if err != nil { return } err = post.delete() if err != nil { return } w.writeheader(200) return }
以下是操作数据库的data.go文件内容:
package main import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) type post struct { id int `json:"id"` content string `json:"content"` author string `json:"author"` } var db *sql.db func init() { var err error db, err = sql.open("mysql", "root:p@ssword1!@tcp(192.168.100.21:3306)/blog") if err != nil { panic(err) } } func retrieve(id int) (post post, err error) { post = post{} err = db.queryrow("select id, content, author from posts where id = ?", id).scan(&post.id, &post.content, &post.author) return } func (post *post) create() (err error) { statement := "insert into posts (content, author) values (?, ?)" stmt, err := db.prepare(statement) if err != nil { return } defer stmt.close() res, err := stmt.exec(post.content, post.author) if err != nil { return } lastid, err := res.lastinsertid() if err != nil { return } post.id = int(lastid) return } func (post *post) update() (err error) { _, err = db.exec("update posts set content = ?, author = ? where id = ?", post.content, post.author, post.id) return } func (post *post) delete() (err error) { _, err = db.exec("delete from posts where id = ?", post.id) return }
上一篇: 四、模块与包&常用模块
下一篇: CSS盒模型的介绍
推荐阅读
-
通过HttpClient 调用ASP.NET Web API示例
-
C#使用PHP服务端的Web Service通信实例
-
c# JSON返回格式的WEB SERVICE
-
更改Web Service部署生成的App_Code.dll名称的方法
-
AngularJS实现与Java Web服务器交互操作示例【附demo源码下载】
-
使用Python的Flask框架构建大型Web应用程序的结构示例
-
HTTP协议下用Web Service上传大文件的解决方案
-
Win2003 WinHTTP Web Proxy Auto-Discovery Service 导致的服务器重启
-
Java web实现动态图片验证码的示例代码
-
使用Python的Scrapy框架编写web爬虫的简单示例