经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
Go Web:RESTful web service示例
来源:cnblogs  作者:骏马金龙  时间:2018/12/10 9:43:49  对本文有异议

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或者请求报文传递

  1. POST /transaction HTTP/1.1
  2. Host: 127.0.0.1
  3.   
  4. 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中不能包含动词,只通过资源来完成动作逻辑

  1. package main
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "path"
  6. "strconv"
  7. )
  8. func main() {
  9. server := http.Server{
  10. Addr: "127.0.0.1:8080",
  11. }
  12. http.HandleFunc("/posts/", handleRequest)
  13. server.ListenAndServe()
  14. }
  15. func handleRequest(w http.ResponseWriter, r *http.Request) {
  16. var err error
  17. switch r.Method {
  18. case "GET":
  19. err = handleGet(w, r)
  20. case "POST":
  21. err = handlePost(w, r)
  22. case "PUT":
  23. err = handlePut(w, r)
  24. case "DELETE":
  25. err = handleDelete(w, r)
  26. }
  27. if err != nil {
  28. http.Error(w, err.Error(), http.StatusInternalServerError)
  29. return
  30. }
  31. }
  32. func handleGet(w http.ResponseWriter, r *http.Request) (err error) {
  33. id, err := strconv.Atoi(path.Base(r.URL.Path))
  34. if err != nil {
  35. return
  36. }
  37. post, err := retrieve(id)
  38. if err != nil {
  39. return
  40. }
  41. output, err := json.MarshalIndent(&post, "", "\t\t")
  42. if err != nil {
  43. return
  44. }
  45. w.Header().Set("Content-Type", "application/json")
  46. w.Write(output)
  47. return
  48. }
  49. func handlePost(w http.ResponseWriter, r *http.Request) (err error) {
  50. len := r.ContentLength
  51. body := make([]byte, len)
  52. r.Body.Read(body)
  53. var post Post
  54. json.Unmarshal(body, &post)
  55. err = post.create()
  56. if err != nil {
  57. return
  58. }
  59. w.WriteHeader(200)
  60. return
  61. }
  62. func handlePut(w http.ResponseWriter, r *http.Request) (err error) {
  63. id, err := strconv.Atoi(path.Base(r.URL.Path))
  64. if err != nil {
  65. return
  66. }
  67. post, err := retrieve(id)
  68. if err != nil {
  69. return
  70. }
  71. len := r.ContentLength
  72. body := make([]byte, len)
  73. r.Body.Read(body)
  74. json.Unmarshal(body, &post)
  75. err = post.update()
  76. if err != nil {
  77. return
  78. }
  79. w.WriteHeader(200)
  80. return
  81. }
  82. func handleDelete(w http.ResponseWriter, r *http.Request) (err error) {
  83. id, err := strconv.Atoi(path.Base(r.URL.Path))
  84. if err != nil {
  85. return
  86. }
  87. post, err := retrieve(id)
  88. if err != nil {
  89. return
  90. }
  91. err = post.delete()
  92. if err != nil {
  93. return
  94. }
  95. w.WriteHeader(200)
  96. return
  97. }

以下是操作数据库的data.go文件内容:

  1. package main
  2. import (
  3. "database/sql"
  4. _ "github.com/go-sql-driver/mysql"
  5. )
  6. type Post struct {
  7. Id int `json:"id"`
  8. Content string `json:"content"`
  9. Author string `json:"author"`
  10. }
  11. var Db *sql.DB
  12. func init() {
  13. var err error
  14. Db, err = sql.Open("mysql", "root:P@ssword1!@tcp(192.168.100.21:3306)/blog")
  15. if err != nil {
  16. panic(err)
  17. }
  18. }
  19. func retrieve(id int) (post Post, err error) {
  20. post = Post{}
  21. err = Db.QueryRow("select id, content, author from posts where id = ?", id).Scan(&post.Id, &post.Content, &post.Author)
  22. return
  23. }
  24. func (post *Post) create() (err error) {
  25. statement := "insert into posts (content, author) values (?, ?)"
  26. stmt, err := Db.Prepare(statement)
  27. if err != nil {
  28. return
  29. }
  30. defer stmt.Close()
  31. res, err := stmt.Exec(post.Content, post.Author)
  32. if err != nil {
  33. return
  34. }
  35. lastid, err := res.LastInsertId()
  36. if err != nil {
  37. return
  38. }
  39. post.Id = int(lastid)
  40. return
  41. }
  42. func (post *Post) update() (err error) {
  43. _, err = Db.Exec("update posts set content = ?, author = ? where id = ?", post.Content, post.Author, post.Id)
  44. return
  45. }
  46. func (post *Post) delete() (err error) {
  47. _, err = Db.Exec("delete from posts where id = ?", post.Id)
  48. return
  49. }
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号