go restful 安全_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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值