RESTful风格
带着问题,找答案:
通过本片文章,你会了解以下四点。并且我会给出go语言的实现案例。
1、了解restful风格的来源、起源、演变史
2、了解restful风格的定义、含义
3、掌握restful风格的简单运用
4、做一个小demo
在restful中前进,是一个非常有趣的过程。
一、他打哪来?为解决什么而去?
1、他爹是谁?
是个叫Roy Fielding的博士,是曾经参与开发http协议(现在上网的基础规则)的主力之一。
2、为啥发明?
2000年那会,网上资源凌乱不堪。传递信息时。前后端交互时,乱操作http (如:用GET、POST乱传参数)。大佬不愧是大佬,roy fielding博士,敏锐的发现这一点。并在自己的论文中书写出了一种规则(风格)。试图平息这场混乱。(“让网络资源,能像图书馆中的书记一样管理”)
目标是:让Web服务 简单、可扩展(加服务器就能扛更多人访问)、无状态(服务器不记仇,每次请求独立)
二、restful的具体表现?
1、一切皆“资源”
互联网上的(用户、订单、图片...),每个资源都有一个唯一地址(URL),
比如: http://api.com/users (代表所有用户)
2、用HTTP动词操作资源
动作 | HTTP动词 | 例子 | 作用 |
---|---|---|---|
查 | GET | GET /users/101 | 获取101号用户信息 |
增 | POST | POST /users | 创建新用户 |
改(全量) | PUT | PUT /users/101 | 更新101号全部信息 |
删 | DELETE | DELETE /users/101 | 删除101号用户 |
改(局部) | PATCH | PATCH /users/101 | 只改用户昵称 |
3、返回必带状态码
- 200 ok:成功
- 201 Created:创建成功
- 404 Not Found:资源不存在
....
三、Restful的意义!
1、结束乱的时代,从前url随意设定。如:/getUser?id=1、/delete_order?oid=2...
现在通过URL+HTTP动词,让全天下的程序员都能看懂。
2、只要按照这一套标准、这同一种风格。无论是go还是C、C++、Java等其他语言。都能通过接口调用,流畅的配合实现某种功能。
3、幂等安全:幂-就是多次。同一操作,连续执行多次,效果是一样的。如delete一个条数据多次,效果与仅delete一次,是相同的。
在进行实战演练前,你需要掌握(go基础知识、http相关知识、数据库相关知识)
四、实战演练
跟着本博主的思路,一点一点来,包教会。
第一步:通过一个及其简单的代码入门。
1、入门版:
目标:掌握·通过http动词的变换进行不同的操作。
package mainimport ("encoding/json""net/http"
)// 用户结构体
type User struct {ID int `json:"id"`Name string `json:"name"`
}// 内存存储(代替数据库)
var users = []User{{ID: 1, Name: "张三"},{ID: 2, Name: "李四"},
}func main() {// 注册路由:处理 /users 的所有请求http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {// 设置响应头(告诉客户端返回的是JSON)w.Header().Set("Content-Type", "application/json")switch r.Method {case "GET": // 获取用户列表json.NewEncoder(w).Encode(users)case "POST": // 创建新用户var newUser User// 解析客户端发来的JSON数据if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {w.WriteHeader(http.StatusBadRequest) // 400 错误return}// 模拟ID生成newUser.ID = len(users) + 1users = append(users, newUser)w.WriteHeader(http.StatusCreated) // 201 创建成功json.NewEncoder(w).Encode(newUser)default:w.WriteHeader(http.StatusMethodNotAllowed) // 405 不允许的方法}})// 启动服务器(端口8080)http.ListenAndServe(":8080", nil)
}
2、基础版:
将入门版本的拓展开来:通过函数调用实现。
package mainimport ("encoding/json" // 用于JSON处理"fmt" // 格式化输出"log" // 日志记录"net/http" // HTTP服务
)// 定义用户结构体(相当于数据模型)
type User struct {ID int `json:"id"` // 用户IDName string `json:"name"` // 用户名
}// 内存数据库(暂时替代真实数据库)
var users = []User{{ID: 1, Name: "小明"},{ID: 2, Name: "小红"},
}func main() {fmt.Println("👉 启动RESTful服务器: http://localhost:8080")// 注册路由:当访问 /users 时触发处理函数http.HandleFunc("/users", usersHandler)// 启动服务器(监听8080端口)log.Fatal(http.ListenAndServe(":8080", nil))
}// 处理/users路由的请求
func usersHandler(w http.ResponseWriter, r *http.Request) {// 设置响应头(告诉浏览器返回的是JSON)w.Header().Set("Content-Type", "application/json")switch r.Method {case "GET": // 处理GET请求(查询用户)handleGetUsers(w, r)case "POST": // 处理POST请求(创建用户)handleCreateUser(w, r)default: // 其他请求方法不允许w.WriteHeader(http.StatusMethodNotAllowed) // 405错误fmt.Fprintf(w, `{"error": "不支持该方法"}`)}
}// 处理GET请求(获取所有用户)
func handleGetUsers(w http.ResponseWriter, r *http.Request) {// 将用户列表转为JSON格式jsonData, err := json.Marshal(users)if err != nil {w.WriteHeader(http.StatusInternalServerError) // 500错误fmt.Fprintf(w, `{"error": "数据转换失败"}`)return}// 返回JSON数据w.Write(jsonData)
}// 处理POST请求(创建新用户)
func handleCreateUser(w http.ResponseWriter, r *http.Request) {// 1. 解析请求中的JSON数据var newUser Usererr := json.NewDecoder(r.Body).Decode(&newUser)if err != nil {w.WriteHeader(http.StatusBadRequest) // 400错误fmt.Fprintf(w, `{"error": "无效的JSON数据"}`)return}// 2. 简单的数据验证if newUser.Name == "" {w.WriteHeader(http.StatusBadRequest)fmt.Fprintf(w, `{"error": "用户名不能为空"}`)return}// 3. 生成新ID(实际项目中数据库会自动生成)newUser.ID = len(users) + 1// 4. 添加到用户列表users = append(users, newUser)// 5. 返回创建成功的响应w.WriteHeader(http.StatusCreated) // 201状态码json.NewEncoder(w).Encode(newUser)
}
原理图:
客户端 (浏览器/curl)│▼HTTP请求(GET/POST)│▼Go服务器 (main.go)│├── GET /users → 返回用户列表│└── POST /users → 创建新用户│ ├── 解析JSON│ ├── 验证数据│ └── 添加到内存│▼HTTP响应(JSON数据)
3、进阶版:
添加获取单个用户功能GET / users / {id} )(如:get/users/1)
// 在main函数中添加新路由
func main() {// ...原有代码...http.HandleFunc("/users/", userHandler) // 添加带ID的路由
}// 新增处理函数
func userHandler(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")// 从路径中提取ID:/users/123 → 123idStr := strings.TrimPrefix(r.URL.Path, "/users/")id, err := strconv.Atoi(idStr)if err != nil {w.WriteHeader(http.StatusBadRequest)fmt.Fprintf(w, `{"error": "无效的用户ID"}`)return}// 查找用户var foundUser *Userfor _, u := range users {if u.ID == id {foundUser = &ubreak}}if foundUser == nil {w.WriteHeader(http.StatusNotFound) // 404fmt.Fprintf(w, `{"error": "用户不存在"}`)return}json.NewEncoder(w).Encode(foundUser)
}
恭喜走出新手村!
到这里,差不多,大家就已经明白了Restful风格是什么?怎么用。
后续若抽出时间,我会继续更新呦~😉
谨记:
RESTful = 用HTTP动词(GET/POST...)操作网络资源(URI标识),
目标是简单、统一、好扩展。
简称:"动词操作资源地址",记住这点,你对restful的理解就能掌握90%了