从POST解析JSON

I've tried to be as descriptive as I can be. If I wasn't specific enough about something, please let me know and I will further explain.

Thanks in advance!

Explanation

I am trying to parse JSON data passed in the body of a POST request to my server. The client side request is being made from a web app written using React, the endpoint is on a server written in Go (code below). The server is correctly parsing the JSON data using a struct as a model, but only after it prints an error "unexpected end of JSON input" as well as an empty array (output below). I only print the parsed JSON once though, so I have no clue why this is happening. Also, if I follow up the POST with the same call multiple times, the behavior is correct sometimes.

The output of the log in the save function is:

[{user: "username", attribute: "playlist", match: true, value: "playlistID"}]

The output below was created when pressing the save button rapidly, therefore making the POST request many times. If I were to just press the save button once the output would be:

unexpected end of JSON input
[]
[{username playlist true playlistID}]

Output

[{username playlist true playlistID}]
[{username playlist true playlistID}]
unexpected end of JSON input
[]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
unexpected end of JSON input
[]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]
[{username playlist true playlistID}]

Client Code

Save Button function

save = () => {
    var rules = [];
    this.state.rules.map((rule, index) => {
        var match = rule.matches[rule.state.match];
        var value = rule.values[rule.state.value];
        var newRule = {
            user: this.props.user,
            attribute: rule.attribute,
            match: match,
            value: value.UUID
        };
        rules.push(newRule);
        return newRule;
    });
    console.log(rules);
    Server.saveSmartPlaylist(rules);
};

Server from above

export function saveSmartPlaylist(data) {
    return axios({
        method: "POST",
        baseURL: "http://localhost:8080",
        url: "/smartplaylist",
        data: data
    }).catch(err => {
        console.log(err);
    });
}

Server Code

Endpoint function

func Playlists(response http.ResponseWriter, request *http.Request) {
    body, err := ioutil.ReadAll(request.Body)
    if err != nil {
        fmt.Println(err)
    }

    var rules []rule
    err = json.Unmarshal(body, &rules)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(rules)

    rest.PostRequest(response, request, rules)
}

Helper function

func PostRequest(response http.ResponseWriter, request *http.Request, v interface{}) {
    response.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    response.Header().Set("Access-Control-Allow-Origin", "*")
    response.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
    response.Header().Set("Content-Type", "application/json")

    enc := json.NewEncoder(response)
    enc.SetEscapeHTML(false)
    enc.Encode(v)
}

Guarding the actual usage of the parsed JSON inside an if that checks the request method solved my problem.

func Playlists(response http.ResponseWriter, request *http.Request) {
    var rules []rule
    if request.Method == http.MethodPost {
        body, err := ioutil.ReadAll(request.Body)
        if err != nil {
            fmt.Println(err)
        }

        err = json.Unmarshal(body, &rules)
        if err != nil {
            fmt.Println(err)
        }

        var tracks []string
        var userID string
        for i := 0; i < len(rules); i++ {
            rule := rules[i]
            ruleTracks := PlaylistMatchValue(rule.User, rule.Match, rule.Value)
            tracks = ruleTracks
            userID = rule.User
        }

        updatePlaylist(userID, tracks)
    }

    rest.PostRequest(response, request, rules)
}

There is no need to ioutil.ReadAll(request.Body) Better to

dec := json.NewDecoder(request.Body) err = dec.Decode(&rules)