go - Golang http 服务器根据内容类型返回 html 或 json
问题描述
我正在尝试使用 gorilla mux 在 Golang 中编写简单的 RESTful 应用程序。我写了几个如下所示的处理程序:
func getUser(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Content-type") == "application/json" {
w.Header().Set("Content-Type", "application/json")
u, err := _getUser(r)
if err != nil {
http.NotFound(w, r)
return
}
json.NewEncoder(w).Encode(u) //asked for json, return json
} else {
w.Header().Set("Content-Type", "text/html")
u, err := _getUser(r)
if err != nil {
http.NotFound(w, r)
return
}
renderTemplate(w, "view", u) // asked for html, return html
}
}
func _getUser(r *http.Request) (*User, error) {
params := mux.Vars(r)
for _, u := range users {
if u.ID == params["id"] {
return &u, nil
}
}
return nil, errors.New("")
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/v1/users/{id}", getUser).Methods("GET")
}
我遇到的问题是我有很多重复。每个 CRUD 方法都必须检查内容类型并返回 json 或 html。
我想过写一个闭包
func htmlOrJSON(fn func(http.ResponseWriter, *http.Request) (interface {}, error), templateName string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Content-type") == "application/json" {
w.Header().Set("Content-Type", "application/json")
result, err := fn(w, r)
if err != nil {
http.NotFound(w, r)
return
}
json.NewEncoder(w).Encode(result)
} else {
w.Header().Set("Content-Type", "text/html")
result, err := fn(w, r)
if err != nil {
http.NotFound(w, r)
return
}
renderTemplate(w, templateName, result)
}
}
}
// and use as:
router.HandleFunc("/v1/users/{id}", htmlOrJSON(getUser, "view")).Methods("GET")
删除重复,但它也看起来不太好。谁能帮我使这段代码更干净?
解决方案
虽然这是一个代码审查问题并且应该在 CodeReview 社区中,但我会尝试回答它。
编写一个处理 HTML 和 JSON 呈现的通用函数。即使您复制了一些代码,错误处理 IMO 也应该发生在每个处理程序上。它在那里更有意义,并使代码更具可读性和明确性。您很快就会发现还有其他需要特殊处理的错误。
在逻辑上,大多数 API 都接受查询参数http://api.com/user/1?fomtat=json
。这更有意义,因为当客户端接受的内容类型多于内容类型时,您将被卡住。
const JSON = "application/json"
func getUser(w http.ResponseWriter, r *http.Request) {
u, err := _getUser(r)
if err != nil {
http.NotFound(w, r)
return
}
responseBody(u, r.Header.Get("Content-type"), &w)
}
func responseBody(u User, contentType string, w io.writer) {
switch contentType {
case JSON:
w.Header().Set("Content-Type", JSON)
json.NewEncoder(w).Encode(u) //asked for json, return json
default:
w.Header().Set("Content-Type", "text/html")
renderTemplate(w, "view", u) // asked for html, return html
}
}
推荐阅读
- google-cloud-firestore - 如何在 SwiftUI 中的 firebase 查询期间显示加载动画
- javascript - 如何判断一个数是否为负数,包括-0
- docker - usermod 命令大大增加了 Docker 容器的大小
- accessibility - 正确隐藏键盘和屏幕阅读器的内容
- powershell - 运行 Power shell exe 并在该 exe 中执行某些步骤
- python - 使用 %run file.py 保存答案
- visual-studio - 如何使用通过 MSVS 构建的 json 设置自动化 CMake 项目?
- c# - 将 web.config 文件添加到 Asp.Net Core 项目
- javascript - 对象中的基元更新但对象中的数组不更新
- html - 不再缩略图博客文章