Go kullanarak bir JSON yanıtı nasıl sunulur?


95

Soru: Şu anda benim tepkisini dışarı yazdırdığımı func Index böyle fmt.Fprintf(w, string(response)) ancak, nasıl bu kadar belki bir görünüm tarafından tüketilen bu isteğe uygun şekilde JSON gönderebilir?

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, "", "  ")
}

github.com/unrolled/render da yardımcı olabilir.
elithrar

Yanıtlar:


128

İçerik türü başlığınızı, müşterilerin json bekleyeceğini bilecek şekilde ayarlayabilirsiniz.

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

Bir yapıyı json'a sıralamanın başka bir yolu, bir kodlayıcı oluşturmaktır. http.ResponseWriter

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

11
w.Header().Set("Content-Type", "application/json")İçerik türünü ayarlamak için doğru olsa da , kullanırken json.NewEncoderbunun yerine bir txt / düz sonuç alıyorum. Başka biri bunu alıyor mu? @Poorva gelen cevap olarak beklenen çalıştı
Jaybeecave

2
Kaşı onu. Kullanırsam w.WriteHeader(http.StatusOk) yukarıdaki sonucu alırım.
Jaybeecave

4
Ben kullanırsanız w.WriteHeader(http.StatusOk)o zaman olsun text/plain; charset=utf-8ben açıkça alıyorum Durum-Kod set Yüklü eğer, applicaton/jsonve Tepki hala Status-Code 200 sahiptir
Ramon Rambo

1
Hmmm ... Bu dokümanlar ile ilgisi olabilir burada ? 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")Yukarıdakileri json.NewEncoder(w).Encode(p)benim için eklemek
Ardi Nusawan

35

Bu yorumlama Diğer kullanıcılar Content-Typeise plain/textkodlarken. Sen ayarlamak zorunda Content-Typebirinci w.Header().Set, ardından HTTP yanıt kodu w.WriteHeader.

Eğer ararsanız w.WriteHeaderilk önce çağrı w.Header().Setalırsınız sonra plain/text.

Örnek bir işleyici şöyle görünebilir;

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)
}

Programım paniğe kapılırsa nasıl yanıt verilir? Recovery () kullanmayı denedim, sonra geri döndüm ama işe yaramadı.
infiniteLearner

28

getJsonResponseİşlevinizde buna benzer bir şey yapabilirsiniz -

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

2
Bu sürümle ilgili önemli bir not jData, muhtemelen gereksiz yere bir bayt dilimi kullanmasıdır . DataSıralanan verilere bağlı olarak keyfi boyutta olabilir, bu nedenle bu önemsiz olmayan bir bellek temizleyicisi olabilir. Sıralamadan sonra, bellekten ResponseWriterakışa kopyalarız . Json.NewEncoder () vb. Kullanan yanıt, sıralı JSON'u doğrudan ResponseWriter(akışına ..)
yazacaktır

1
Benim için çalıştı! 'W.WriteHeader (http.StatusCreated)' öncesine veya sonrasına eklendiğinde sorunla karşılaşıldı.
darkdefender27

1
Programınızdan çıktığı için panikten sonra geri dönmenize gerek yok
andersfylling

En azından bu çözüm, Encoder.Encode()işlevin \ n
Jonathan Muller

2

Gobuffalo.io çerçevesinde şu şekilde çalışmasını sağladım:

// 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"))
}

ve sonra o kaynak için JSON yanıtı almak istediğimde "Content-type" ı "application / json" olarak ayarlamam gerekiyor ve çalışıyor.

Bence Rails'in birden fazla yanıt türünü ele almak için daha uygun bir yolu var, şimdiye kadar gobuffalo'da aynı şeyi görmedim.


0

Bu paket oluşturucuyu kullanabilirsiniz , bu tür bir sorunu çözmek için yazdım, JSON, JSONP, XML, HTML vb. Sunmak için bir sarmalayıcıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.