Làm cách nào để gửi phản hồi JSON bằng Go?


95

Câu hỏi: Tuy nhiên, hiện tại tôi đang in phản hồi của mình ở dạng func Index như thế này fmt.Fprintf(w, string(response)) , làm cách nào để gửi JSON đúng cách trong yêu cầu để nó có thể được xem bởi một lượt xem?

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 cũng có thể hữu ích.
elithrar

Câu trả lời:


127

Bạn có thể đặt tiêu đề loại nội dung của mình để khách hàng biết họ mong đợi json

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

Một cách khác để điều chỉnh cấu trúc thành json là tạo một bộ mã hóa bằng cách sử dụng http.ResponseWriter

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

11
Mặc dù w.Header().Set("Content-Type", "application/json")đúng cho việc thiết lập loại nội dung, nhưng khi sử dụng json.NewEncoderthay vào đó, tôi không nhận được kết quả txt / clear. Có ai khác hiểu điều này không. Câu trả lời từ @poorva đã làm việc như mong đợi
Jaybeecave

2
Cào đó. Nếu tôi sử dụng, w.WriteHeader(http.StatusOk) tôi nhận được kết quả trên.
Jaybeecave

4
Nếu tôi sử dụng w.WriteHeader(http.StatusOk)sau đó tôi nhận được text/plain; charset=utf-8, nếu Tôi không đặt tình trạng-Code rõ ràng tôi nhận được applicaton/jsonvà đáp ứng vẫn có Status-Code 200.
Ramon Rambo

1
Hmmm ... nó có thể liên quan đến các tài liệu ở đây ? Changing the header map after a call to WriteHeader (or Write) has no effect unless the modified headers are trailers.
Dan Esparza

2
Thêm công việc w.Header().Set("Content-Type", "application/json")ở trên json.NewEncoder(w).Encode(p)cho tôi
Ardi Nusawan

34

Những người dùng khác nhận xét rằng đó Content-Typeplain/textkhi mã hóa. Bạn phải đặt mã phản hồi Content-Typeđầu tiên w.Header().Set, sau đó là mã phản hồi HTTP w.WriteHeader.

Nếu bạn gọi w.WriteHeadertrước thì hãy gọi w.Header().Setsau bạn sẽ nhận được plain/text.

Một trình xử lý ví dụ có thể trông như thế này;

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

Làm thế nào để trả lại phản hồi, nếu chương trình của tôi bị rối loạn? Tôi đã thử sử dụng recovery (), sau đó quay lại từ của họ nhưng không thành công.
infiniteLearner

28

Bạn có thể làm điều gì đó như thế này trong getJsonResponsechức năng của bạn -

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

2
Một lưu ý quan trọng về phiên bản này là nó sử dụng một lát byte jData, có thể không cần thiết. Datacó thể có kích thước tùy ý, tùy thuộc vào dữ liệu được sắp xếp, vì vậy đây có thể là một bộ nhớ không tầm thường. Sau khi điều chỉnh, chúng tôi sao chép từ bộ nhớ vào ResponseWriterluồng. Câu trả lời sử dụng json.NewEncoder (), v.v. sẽ ghi JSON được điều chỉnh ngay vào ResponseWriter(vào luồng của nó ..)
Jonno

1
Đã làm cho tôi! Đối mặt với sự cố khi 'w.WriteHeader (http.StatusCreate)' được thêm vào trước hoặc sau đó.
darkdefender27

1
Không cần phải quay lại sau khi hoảng sợ vì điều này thoát khỏi chương trình của bạn
andersfylling

Ít nhất giải pháp này không thêm dấu \ n của Encoder.Encode()hàm số
Jonathan Muller

2

Trong khung gobuffalo.io, tôi đã làm cho nó hoạt động như sau:

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

và sau đó khi tôi muốn nhận được phản hồi JSON cho tài nguyên đó, tôi phải đặt "Loại nội dung" thành "ứng dụng / json" và nó hoạt động.

Tôi nghĩ rằng Rails có cách thuận tiện hơn để xử lý nhiều loại phản hồi, tôi không thấy điều tương tự trong gobuffalo cho đến nay.


0

Bạn có thể sử dụng trình kết xuất gói này , tôi đã viết để giải quyết loại vấn đề này, đó là trình bao bọc để phục vụ JSON, JSONP, XML, HTML, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.