Câu hỏi Xử lý yêu cầu đăng bài JSON trong khi truy cập


Vì vậy, tôi có những điều sau đây, có vẻ vô cùng khó khăn, và tôi đã tự nghĩ rằng Go có các thư viện được thiết kế tốt hơn điều này, nhưng tôi không thể tìm thấy ví dụ về Go xử lý yêu cầu POST của dữ liệu JSON. Tất cả đều là POST.

Đây là một yêu cầu ví dụ: curl -X POST -d "{\"test\": \"that\"}" http://localhost:8082/test

Và đây là mã, với các bản ghi được nhúng:

package main

import (
    "encoding/json"
    "log"
    "net/http"
)

type test_struct struct {
    Test string
}

func test(rw http.ResponseWriter, req *http.Request) {
    req.ParseForm()
    log.Println(req.Form)
    //LOG: map[{"test": "that"}:[]]
    var t test_struct
    for key, _ := range req.Form {
        log.Println(key)
        //LOG: {"test": "that"}
        err := json.Unmarshal([]byte(key), &t)
        if err != nil {
            log.Println(err.Error())
        }
    }
    log.Println(t.Test)
    //LOG: that
}

func main() {
    http.HandleFunc("/test", test)
    log.Fatal(http.ListenAndServe(":8082", nil))
}

Phải có một cách tốt hơn, đúng không? Tôi chỉ bối rối trong việc tìm kiếm những gì thực hành tốt nhất có thể được.

(Go còn được gọi là Golang cho các công cụ tìm kiếm và được đề cập ở đây để những người khác có thể tìm thấy nó.)


180
2018-03-28 01:16


gốc


nếu bạn dùng curl -X POST -H 'Content-Type: application/json' -d "{\"test\": \"that\"}", sau đó req.Form["test"] nên quay trở lại "that" - Vinicius
@Vinicius có bằng chứng nào về điều này không? - diraria


Các câu trả lời:


Vui lòng sử dụng json.Decoder thay vì json.Unmarshal.

func test(rw http.ResponseWriter, req *http.Request) {
    decoder := json.NewDecoder(req.Body)
    var t test_struct
    err := decoder.Decode(&t)
    if err != nil {
        panic(err)
    }
    log.Println(t.Test)
}

281
2018-03-28 15:11



Bạn có thể giải thích tại sao không? - Ryan Bigg
Để bắt đầu, có vẻ như điều này có thể xử lý một luồng thay vì cần bạn tải tất cả vào bộ đệm. (Tôi là một Joe BTW khác) - Joe
Tôi tự hỏi cách xử lý lỗi thích hợp sẽ trông như thế nào trong trường hợp này. Tôi không nghĩ rằng nó là một ý tưởng tốt để hoảng sợ trên một json không hợp lệ. - codepushr
Tôi không nghĩ bạn cần defer req.Body.Close() Từ các tài liệu: "Máy chủ sẽ đóng phần thân yêu cầu. Trình xử lý ServeHTTP không cần." Ngoài ra để trả lời @thisisnotabus, từ các tài liệu: "Đối với các yêu cầu máy chủ, Request Body luôn không phải là Nil nhưng sẽ trả về EOF ngay lập tức khi không có phần thân nào" golang.org/pkg/net/http/#Request - Drew LeSueur
Tôi sẽ đề nghị không sử dụng json.Decoder. Nó dành cho các luồng của các đối tượng JSON, không phải là một đối tượng duy nhất. Nó không hiệu quả hơn đối với một đối tượng JSON vì nó đọc toàn bộ đối tượng vào trong bộ nhớ. Nó có một nhược điểm là nếu rác được bao gồm sau khi đối tượng nó sẽ không phàn nàn. Tùy thuộc vào một vài yếu tố, json.Decodercó thể không đọc toàn bộ nội dung và kết nối sẽ không đủ điều kiện để sử dụng lại. - Kale B


Bạn cần đọc từ req.Body. Các ParseForm phương pháp được đọc từ req.Body và sau đó phân tích nó theo định dạng được mã hóa chuẩn của HTTP. Những gì bạn muốn là đọc nội dung và phân tích cú pháp theo định dạng JSON.

Đây là mã của bạn được cập nhật.

package main

import (
    "encoding/json"
    "log"
    "net/http"
    "io/ioutil"
)

type test_struct struct {
    Test string
}

func test(rw http.ResponseWriter, req *http.Request) {
    body, err := ioutil.ReadAll(req.Body)
    if err != nil {
        panic(err)
    }
    log.Println(string(body))
    var t test_struct
    err = json.Unmarshal(body, &t)
    if err != nil {
        panic(err)
    }
    log.Println(t.Test)
}

func main() {
    http.HandleFunc("/test", test)
    log.Fatal(http.ListenAndServe(":8082", nil))
}

57
2018-03-28 01:24



Tôi có lẽ chỉ không nhận được nó, nhưng sẽ không chỉ cho tôi trở lại những gì tôi đã có trong req *http.Request? - TomJ
Trên thực tế, tôi đã cập nhật câu trả lời. Câu trả lời đầu tiên của tôi là sai. Tôi đã thử nghiệm cái này. - Daniel
Cảm ơn! Tôi thấy bây giờ tôi đã đi sai. Nếu bạn gọi req.ParseForm(), mà tôi đã làm trong những nỗ lực trước đó của việc cố gắng giải quyết vấn đề này, trước khi bạn thử và đọc req.Body, có vẻ như làm sạch cơ thể và unexpected end of JSON input được ném khi bạn đi đến Unmarshal (ít nhất là trong 1.0.2) - TomJ
@Daniel: Khi tôi làm curl -X POST -d "{\" tes \ ": \" đó \ "}" localhost: 8082 / test, log.Println (t.Test) trả về sản phẩm nào. Tại sao ? Hoặc cho vấn đề đó nếu đăng bất kỳ JSON nào khác, nó sẽ trả về sản phẩm nào - Somesh


Tôi đã lái xe bản thân mình điên với vấn đề này chính xác. JSONer Marshall và Unmarshaller của tôi không có cấu trúc Go của tôi. Sau đó, tôi tìm thấy giải pháp tại https://eager.io/blog/go-and-json:

"Như với tất cả các cấu trúc trong Go, điều quan trọng cần nhớ là chỉ có các trường có chữ cái đầu tiên được hiển thị cho các chương trình bên ngoài như JSON Marshaller."

Sau đó, Marshaller và Unmarshaller của tôi đã làm việc hoàn hảo!


29
2018-03-15 00:01



Người đàn ông tôi đã la hét sau khi giải pháp này làm việc của bạn. Cảm ơn, trời ơi. - AndreaM16
Cảm ơn rất nhiều ! Điều này xứng đáng với ngai vàng - Hadrien Pierre Mazelier
Điều này có vẻ là lỗi khá phổ biến :-) - Panagiotis Atmatzidis


Tôi tìm thấy ví dụ sau từ các tài liệu thực sự hữu ích (nguồn đây).

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    const jsonStream = `
        {"Name": "Ed", "Text": "Knock knock."}
        {"Name": "Sam", "Text": "Who's there?"}
        {"Name": "Ed", "Text": "Go fmt."}
        {"Name": "Sam", "Text": "Go fmt who?"}
        {"Name": "Ed", "Text": "Go fmt yourself!"}
    `
    type Message struct {
        Name, Text string
    }
    dec := json.NewDecoder(strings.NewReader(jsonStream))
    for {
        var m Message
        if err := dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s: %s\n", m.Name, m.Text)
    }
}

Chìa khóa ở đây là OP đang tìm cách giải mã

type test_struct struct {
    Test string
}

... trong trường hợp đó chúng ta sẽ bỏ const jsonStreamvà thay thế Message struct với test_struct:

func test(rw http.ResponseWriter, req *http.Request) {
    dec := json.NewDecoder(req.Body)
    for {
        var t test_struct
        if err := dec.Decode(&t); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        log.Printf("%s\n", t.Test)
    }
}

Cập nhật: Tôi cũng sẽ thêm rằng bài này cũng cung cấp một số dữ liệu tuyệt vời về việc trả lời JSON. Tác giả giải thích struct tagsmà tôi không biết.

Vì JSON thường không giống {"Test": "test", "SomeKey": "SomeVal"}mà đúng hơn là {"test": "test", "somekey": "some value"}, bạn có thể cấu trúc lại cấu trúc của bạn như sau:

type test_struct struct {
    Test string `json:"test"`
    SomeKey string `json:"some-key"`
}

... và bây giờ trình xử lý của bạn sẽ phân tích cú pháp JSON bằng cách sử dụng "một số khóa" thay vì "SomeKey" (mà bạn sẽ sử dụng nội bộ).


13
2018-04-17 01:48



mã không biên dịch. Bạn có nghĩa là req.Body, không r.Body - eyeApps LLC
khác với lỗi đánh máy, những gì bạn đã đưa ra trong bài kiểm tra (), là tôi tin rằng một câu trả lời vượt trội cho một chấp nhận, vì nó không cần thiết tạo ra một chuỗi sao chép - eyeApps LLC
Rất tiếc! Cập nhật lỗi đánh máy - cảm ơn bạn đã chỉ ra! - JohnnyCoder