json.NewEncoder的用法
现在无论是网站、App
、小程序还是移动端H5
页面应用,都是采用前端与后端单独部署,相互之间以API
接口交互的形式构建而成的。因为在结合可读性、编码数据大小和开发者使用难度上都JSON
格式是一个比较好的选择,所以接口的数据格式通常都采用JSON
,即前端在发送POST
,PUT
,PATCH
请求添加,更改数据时会把数据以JSON
格式放到请求的Body
中。而后端则是所有数据都会以JSON
格式返回。
关于JSON
可读性、编码数据大小和开发者使用难度上,因为其可读性不如XML
结构,但是数据量小,用程序操作起来更方便。对比Protobuf
来说,Protobuf
编码速度、编码后数据大小比JSON
都要好,但是用程序操作起来没有JSON
方便简单,编码后的数据是二进制格式的,易读性完全没有。所以整体来说JSON
是一个各个方面都不错更容易被所有人接受才被广泛使用的(以上都是个人观点)。
之前也写过两篇关于用Go
语言解码和编码JSON
数据的文章
那么针对Web
编程我们其实只要关注怎么从HTTP
请求的Body
中读取到JSON
数据,以及如何将要返回给客户端的数据以JSON
格式写入到HTTP
响应中。
从请求体读取JSON数据
关于这部分内容其实在之前的文章深入学习解析HTTP请求里有说过。
我们需要把请求体作为json.NewDecoder()
的输入流,然后将请求体中携带的JSON
格式的数据解析到声明的结构体变量中
//handler/parse_json_request
package handler
import (
"encoding/json"
"fmt"
"net/http"
)
type Person struct {
Name string
Age int
}
func DisplayPersonHandler(w http.ResponseWriter, r *http.Request) {
var p Person
// 将请求体中的 JSON 数据解析到结构体中
// 发生错误,返回400 错误码
err := json.NewDecoder(r.Body).Decode(&p)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Fprintf(w, "Person: %+v", p)
}
// router/router.go
indexRouter.HandleFunc("/parse_json_request", handler.ParseJsonRequestHandler)
在命令行里用cURL
命令测试我们的程序:
curl -X POST -d '{"name": "James", "age": 18}' \
-H "Content-Type: application/json" \
http://localhost:8000/index/parse_json_request
把JSON数据写入响应
与上面相反,将返回数据以JSON
格式写入响应时,我们调用json.NewEncodeer(w).Encode(&v)
,用响应体作为输入流创建JSON
编码器,然后使用其Encode()
方法将数据编码为JSON
格式并写入响应体。
// handler/write_json_response
package handler
import (
"encoding/json"
"net/http"
)
type User struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Age int `json:"age"`
}
func WriteJsonResponseHandler(w http.ResponseWriter, r *http.Request) {
p := User{
FirstName: "John",
LastName: "Doe",
Age: 25,
}
// Set response header
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(&p)
if err != nil {
//... handle error
}
}
// router/router.go
indexRouter.HandleFunc("/get_json_response", handler.WriteJsonResponseHandler)
重启服务器后在命令行里用cURL
命令测试我们的程序:
curl -X GET http://localhost:8000/index/get_json_response
{"firstname":"John","lastname":"Doe","age":25}
今天的内容很简单,源码已经上传,公众号回复gohttp12获取文中源代码的下载链接
写get或post的api接口时需要注意什么?
在编写GET或POST的API接口时,有一些注意事项需要考虑,以确保接口的正确性和安全性:
-
路由和路径参数:在设计API接口时,需要选择合适的路由和路径参数来表示资源的唯一标识符或其他参数。确保路径参数的命名清晰明确,遵循RESTful设计原则。
-
请求方法:使用GET方法用于获取资源,使用POST方法用于创建资源。确保接口的请求方法与其所执行的操作相对应。同时,还可以考虑使用其他HTTP方法(如PUT、DELETE等)来实现不同的操作。
-
请求和响应数据格式:在处理API请求和响应时,需要指定适当的数据格式。常见的数据格式包括JSON、XML、FormData等。确保请求和响应数据格式的一致性,并在响应中设置正确的Content-Type头部。
-
请求参数的验证与解析:对于接收的请求参数,需要进行验证和解析,以确保数据的完整性和有效性。验证可以包括检查参数是否存在、类型是否匹配、范围是否合理等。解析可以使用Go语言的内置包(如
encoding/json
、encoding/xml
等)进行。 -
错误处理和状态码:对于出现错误的情况,需要返回适当的错误信息和HTTP状态码。使用合适的HTTP状态码(如400、404、500等)来指示不同类型的错误。同时,提供清晰明确的错误信息,以便客户端能够正确处理错误情况。
-
安全性考虑:在处理敏感数据或执行敏感操作时,需要考虑安全性。使用HTTPS来保护数据的传输,对敏感数据进行适当的加密和解密,使用身份验证和授权机制来限制访问权限等。
-
并发安全性:如果多个请求同时访问共享资源(如数据库连接、缓存等),需要确保并发安全性。可以使用互斥锁或其他并发控制机制来保护共享资源,避免竞态条件和数据不一致的问题。
-
性能优化:对于高频的API接口,需要考虑性能优化。可以使用缓存、连接池等技术来提高响应速度和吞吐量。同时,合理设计数据库查询、避免不必要的计算和IO操作,以提高接口的性能。
-
日志记录:在API接口中添加适当的日志记录,可以帮助排查问题和分析系统运行情况。记录关键的请求信息、响应时间、错误信息等,以便后续的故障排查和性能优化。
-
单元测试:对于编写的API接口,编写相应的单元测试是一个良好的实践。通过单元测试可以验证接口的功能和正确性,并提早发现潜在的问题。
Go语言如何写api接口
在Go语言中编写API接口可以使用标准库中的"net/http"包。下面是一个简单的示例,演示如何编写GET和POST接口:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
var users []User
func main() {
http.HandleFunc("/users", getUsersHandler)
http.HandleFunc("/users/create", createUserHandler)
fmt.Println("Server is listening on port 8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func getUsersHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// 返回所有用户数据
json.NewEncoder(w).Encode(users)
}
func createUserHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// 解析请求体中的JSON数据
var newUser User
err := json.NewDecoder(r.Body).Decode(&newUser)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// 生成新用户ID
newUser.ID = len(users) + 1
// 添加新用户到列表中
users = append(users, newUser)
// 返回新创建的用户信息
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(newUser)
}
在上面的示例中,我们创建了两个接口:/users
和/users/create
。
getUsersHandler
函数处理GET请求,并返回所有用户数据。它设置响应的Content-Type为application/json
,然后使用json.NewEncoder
将users
切片编码为JSON格式,并写入响应。
createUserHandler
函数处理POST请求,用于创建新用户。它首先解析请求体中的JSON数据,然后生成新用户的ID,并将新用户添加到users
切片中。最后,它设置响应的状态码为201(Created),并将新创建的用户信息编码为JSON格式,写入响应。
在main
函数中,我们使用http.HandleFunc
函数将路由和处理函数进行绑定,然后使用http.ListenAndServe
函数启动HTTP服务器,并指定监听的端口为8080。
你可以使用curl或Postman等工具来测试这些API接口。例如,可以使用以下命令发送GET请求获取用户数据:
curl -X GET http://localhost:8080/users
可以使用以下命令发送POST请求创建新用户:
curl -X POST -H "Content-Type: application/json" -d '{"name":"Alice","age":25}' http://localhost:8080/users/create
以上示例只是一个简单的演示,实际的API接口可能涉及更复杂的业务逻辑和数据持久化操作。
但是基本的GET和POST处理方式是相似的,通过http.Request
对象获取请求参数、路径和请求体数据,然后根据具体需求进行相应的处理和响应。