如何使用Go提供JSON响应?


94

问:目前我打印出我的回应func Index 是这样fmt.Fprintf(w, string(response)) 但是,我怎么能正确地在请求发送JSON,以便它可能由视图消耗?

package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "net/http"
    "log"
    "encoding/json"
)

type Payload struct {
    Stuff Data
}
type Data struct {
    Fruit Fruits
    Veggies Vegetables
}
type Fruits map[string]int
type Vegetables map[string]int


func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    response, err := getJsonResponse();
    if err != nil {
        panic(err)
    }
    fmt.Fprintf(w, string(response))
}


func main() {
    router := httprouter.New()
    router.GET("/", Index)
    log.Fatal(http.ListenAndServe(":8080", router))
}

func getJsonResponse()([]byte, error) {
    fruits := make(map[string]int)
    fruits["Apples"] = 25
    fruits["Oranges"] = 10

    vegetables := make(map[string]int)
    vegetables["Carrats"] = 10
    vegetables["Beets"] = 0

    d := Data{fruits, vegetables}
    p := Payload{d}

    return json.MarshalIndent(p, "", "  ")
}

Answers:


126

您可以设置内容类型标头,以便客户知道期望json

w.Header().Set("Content-Type", "application/json")

将结构封送至json的另一种方法是使用 http.ResponseWriter

// get a payload p := Payload{d}
json.NewEncoder(w).Encode(p)

11
虽然w.Header().Set("Content-Type", "application/json")对于设置内容类型是正确的,但使用json.NewEncoder替代项却没有,我得到了txt /纯文本结果。还有其他人得到这个吗?@poorva的答案按预期的那样工作
Jaybeecave

2
刮一下。如果我使用w.WriteHeader(http.StatusOk) 我得到以上结果。
Jaybeecave

4
如果我使用w.WriteHeader(http.StatusOk),然后我得到的text/plain; charset=utf-8,如果我不设置状态码明确我得到applicaton/json和响应仍具有状态码200
拉蒙·兰博

1
嗯...可能和这里的文档有关吗? Changing the header map after a call to WriteHeader (or Write) has no effect unless the modified headers are trailers.
Dan Esparza

2
为我添加w.Header().Set("Content-Type", "application/json")以上json.NewEncoder(w).Encode(p)工作
Ardi Nusawan

34

其他用户评论的Content-Typeplain/text编码时。你必须设置的Content-Type第一w.Header().Set,那么HTTP响应代码w.WriteHeader

如果您w.WriteHeader先打电话w.Header().Set,然后再打电话,您会得到plain/text

一个示例处理程序可能看起来像这样;

func SomeHandler(w http.ResponseWriter, r *http.Request) {
    data := SomeStruct{}
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(data)
}

如果我的程序出现紧急情况,如何返回响应?我尝试使用restore(),然后从他们返回但没有成功。
infiniteLearner

27

您可以在getJsonResponse函数中执行以下操作-

jData, err := json.Marshal(Data)
if err != nil {
    // handle error
}
w.Header().Set("Content-Type", "application/json")
w.Write(jData)

2
关于此版本的一个重要说明是,它jData可能在中不必要地使用了字节片。Data可以具有任意大小,具体取决于要整理的数据,因此这可能是不平凡的内存浪费。编组后,我们从内存复制到ResponseWriter流。使用json.NewEncoder()等的答案会将编组的JSON直接写入ResponseWriter(放入其流中。)
Jonno

1
为我工作!在之前或之后添加“ w.WriteHeader(http.StatusCreated)”时遇到的问题。
darkdefender17年

1
退出程序后,无需在出现恐慌后返回
Andersfylling,2017年

至少此解决方案未添加Encoder.Encode()函数的尾随\ n
Jonathan Muller

2

在gobuffalo.io框架中,我可以像这样工作:

// say we are in some resource Show action
// some code is omitted
user := &models.User{}
if c.Request().Header.Get("Content-type") == "application/json" {
    return c.Render(200, r.JSON(user))
} else {
    // Make user available inside the html template
    c.Set("user", user)
    return c.Render(200, r.HTML("users/show.html"))
}

然后,当我想获取该资源的JSON响应时,必须将“ Content-type”设置为“ application / json”,然后才能正常工作。

我认为Rails拥有处理多种响应类型的更便捷方法,到目前为止,我在gobuffalo中没有看到相同的结果。


0

您可以使用此包渲染器,我已经写过解决此问题的方法,它是提供JSON,JSONP,XML,HTML等的包装器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.