由于响应结构的微小变化,重复调用 JSON 解码器

我已将 Github 和 Google 身份验证系统添加到我的 Web 应用程序中。在这两种情况下,我都希望获得用户电子邮件。我尝试制作一个可以发出 API 请求并获取电子邮件的函数。当Google 返回一个 JSON 对象并在 Github 上返回一个 JSON 数组作为响应

时,我遇到了一个问题。 我无法弄清楚如何避免两次调用 JSON 解码器,因为我不能为它们两个使用相同的类型变量。


// Sends a request to the API and

// authorizes it by setting HTTP header "Authorization" to authHeader value

func getUserEmail(endpoint, authHeader, provider string) (string, error) {

    var email string       // Store user email here

    var client http.Client // Create client so we can modify request headers


    // Create a GET request to the endpoint

    req, err := http.NewRequest("GET", endpoint, nil)

    if err != nil {

        return "", err

    }


    // Authorize the request by using the HTTP header

    req.Header.Add("Authorization", authHeader)


    // Give the data back as JSON

    req.Header.Add("accept", "application/json")


    // Send the request

    resp, err := client.Do(req)

    if err != nil {

        fmt.Println("Internet connection or client policy error")

        return "", err

    }

    defer resp.Body.Close()


    if provider == "google" {

        var response map[string]interface{}


        err = json.NewDecoder(resp.Body).Decode(&response)

        if err != nil {

            fmt.Println("Error occured during decoding access token response")

            return "", err

        }


        email = response["email"].(string)


    } else if provider == "github" {

        var response []map[string]interface{}


        err = json.NewDecoder(resp.Body).Decode(&response)

        if err != nil {

            fmt.Println("Error occured during decoding access token response")

            return "", err

        }


        email = response[0]["email"].(string)

    } else {

        return "", errors.New("invalid provider")


    }


    return email, nil

}


犯罪嫌疑人X
浏览 88回答 1
1回答

饮歌长啸

您可以解组为var response interface{}. 一旦 json 被解组,你可以在type assertion上做一个response检查它是否是[]interface{}或map[string]interface{}从那里去。var email stringvar response interface{}if err := json.NewDecoder(r.Body).Decode(&response); err != nil {    return err}// If you are sure that the structure of the content of the response,// given its type, is always what you expect it to be, you can use a// quick-and-dirty type switch/assertion.switch v := response.(type) {case []interface{}:    email = v[0].(map[string]interface{})["email"].(string)case map[string]interface{}:    email = v["email"].(string)}// But! If you're not sure, if the APIs don't provide a guarantee,// then you should guard against panics using the comma-ok idiom// at every step.if s, ok := response.([]interface{}); ok && len(s) > 0 {    if m, ok := s[0].(map[string]interface{}); ok && len(m) > 0 {        email, _ = m["email"].(string)    }} else if m, ok := response.(map[string]interface{}); ok && len(m) > 0 {    email, _ = m["email"].(string)}您还可以根据提供者值预先分配一个指向预期类型的指针,并将请求正文解组到其中,这将减少必要的类型断言的数量,但需要指针解引用。var email stringvar response interface{}if provider == "google" {    response = new(map[string]interface{})} else if provider == "github" {    response = new([]map[string]interface{})}if err := json.NewDecoder(r.Body).Decode(response); err != nil {    return err}switch v := response.(type) {case *[]map[string]interface{}:    email = (*v)[0]["email"].(string) // no need to assert the slice element's typecase *map[string]interface{}:    email = (*v)["email"].(string)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go