Попытка сделать HTTP-запрос и вернуть результат этого запроса в приложении, использующем go/gin

# #go #go-gin

Вопрос:

Я только вчера взял Go, и мне было интересно, как я могу сделать HTTP-запрос и вернуть результат этого запроса с помощью моего API, созданного с помощью Gin.

Это код конечной точки, которая возвращает результат другого запроса

 func ProvideAccessToken(c *gin.Context) {
    body := bindings.RequestAccessTokenBody{}

    err := c.ShouldBind(amp;body)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        log.Println(err)
        return
    }

    if body.Code == "" || body.GrantType == "" || body.RedirectURI == "" {
        c.String(http.StatusBadRequest, "Bad Request")
        return
    }
    res, err := helpers.ExchangeCodeForToken(body.GrantType, body.RedirectURI, body.Code)

    if err != nil {
        c.JSON(res.StatusCode, gin.H{"error": err.Error()})
        return
    }
    defer res.Body.Close()
    c.Header("Content-Type", "application/json")
    c.JSON(200, res.Body)
}
 

Это функция, которая выполняет HTTP-запрос

 func ExchangeCodeForToken(grantType string, redirectUri string, code string) (*http.Response, error) {
    authToken := "Basic "   encodeClientSecretAndId()
    body := url.Values{}
    body.Set("grant_type", grantType)
    body.Set("redirect_uri", redirectUri)
    body.Set("code", code)
    encodedBody := body.Encode()
    client := amp;http.Client{}

    r, _ := http.NewRequest(http.MethodPost, tokenUrl, strings.NewReader(encodedBody))
    r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    r.Header.Add("Authorization", authToken)
    res, err := client.Do(r)
    return res, err
}
 

Когда я использую почтальона для запроса, ответ-это просто пустой json, вот так {} .
Когда измените конец моей ProvideAccessToken функции на

     defer res.Body.Close()
    respbody, err := ioutil.ReadAll(res.Body)
    if err != nil {
        c.JSON(res.StatusCode, gin.H{"error": err.Error()})
        return
    }
    c.Header("Content-Type", "application/json")
    c.JSON(200, string(respbody))
 

Я получаю это в результате "{"error":"invalid_grant","error_description":"Authorization code expired"}" , что правильно, но у него странное форматирование. Я просто хочу вернуть именно то, что возвращает другой API.

Ответ №1:

Первая версия программы кодирует значение тела ответа как JSON. Ответ {}, потому что в теле ответа нет экспортированных полей. Это не то, чего ты хочешь.

Вторая версия программы кодирует ответ JSON как JSON. Странное форматирование — это экранирование " в исходном JSON.

Запишите данные как есть в ответ. Вот модификация второй версии программы:

 defer res.Body.Close()
respbody, err := ioutil.ReadAll(res.Body)
if err != nil {
    c.JSON(res.StatusCode, gin.H{"error": err.Error()})
    return
}
c.Data(200, "application/json", respbody) // <-- note this line
 

Вы также можете копировать из одного ответа в другой:

 defer res.Body.Close()
c.DataFromReader(200, res.ContentLength, "application/json", res.Body, nil)