zoukankan      html  css  js  c++  java
  • 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, "", "		")
    	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
    }
    
  • 相关阅读:
    CSS3自定义滚动条样式 -webkit-scrollbar
    仿flash的文字动画效果
    使用PowerDesigner导出MySQL数据库建模
    将博客搬至CSDN
    centos6.3安装MySQL 5.6(转)
    # mysql -u root -p -bash: mysql: command not found
    win8设置保护眼睛的颜色
    网关末尾要么是1要么是254
    虚机centos和本机Windows之间文件的拷贝无法用xftp时用FileZilla也行
    Java基础知识总结之基础数据类型
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/10082505.html
Copyright © 2011-2022 走看看