Обработка ошибок в Go возвращает пустой объект ошибки в http-ответе

#go

#Вперед

Вопрос:

Я создаю API в go . Все работает нормально, только когда возникает ошибка, я хочу показать ее пользователю. Я использую errors пакет go.

Ниже приведен sample код:

 type ErrorResponse struct {
        Status string `json:"status"`
        Error  error  `json:"error"`
    }
err := errors.New("Total Price cannot be a negative value")
errRes := ErrorResponse{"ERROR", err}
response, errr := json.Marshal(errRes)
if errr != nil {
    log.Fatal(err)
    return
}
io.WriteString(w, string(response))
  

Ответ, который я получаю, является:

 {
  "status": "ERROR",
  "error": {} //why is this empty
}
  

ключ ошибки должен содержать строку Total Price cannot be a negative value . Я не понимаю проблему.

Комментарии:

1. Вы не можете отправить данные после http. Ошибка: См. golang.org/pkg/net/http/#Error . Вы должны отправить string(response) вместо http.StatusText(500) . Это действительно помогает прочитать всю документацию по любой используемой функции.

2. if err != nil { log.Fatal(err) http.Error(w, http.StatusText(500), 500) return } Я не говорю об этой ошибке. Эта обработка ошибок предназначена для сбоя, если json.Marshal . Пожалуйста, прочитайте контекст должным образом, прежде чем отклонять.

3. @Volker Я отредактировал свой вопрос, если вы в замешательстве. Пожалуйста, проверьте.

Ответ №1:

Типы ошибок не могут маршалироваться в JSON. Есть несколько способов обойти это. Если вы не хотите изменять свою ErrorResponse структуру, то практически единственный способ — определить пользовательский MarshalJSON метод для вашей структуры, в котором вы указываете маршалеру использовать строку, возвращаемую .Error() методом ошибки.

 func (resp ErrorResponse) MarshalJSON() ([]byte, error) {
    return json.Marshal(amp;struct {
        Status string `json:"status"`
        Error  string `json:"error"`
    }{
        Status: resp.Status,
        Error:  resp.Error.Error(),
    })
}
  

https://play.golang.org/p/EgVj_4Cc3W

Если вы хотите упорядочить ошибки в JSON и в другом месте. Затем вы могли бы использовать пользовательский тип ошибки и определить маршалинг для этого, например:

 type MyError struct {
    Error error
}

func (err MyError) MarshalJSON() ([]byte, error) {
    return json.Marshal(err.Error.Error())
}
  

https://play.golang.org/p/sjOHj9X0tO

Самый простой (и, вероятно, лучший) способ — просто использовать строку в вашей структуре ответа. Это имеет смысл, потому что фактическое значение, которое вы отправляете в http-ответе, очевидно, является строкой, а не интерфейсом ошибки.

 type ErrorResponse struct {
        Status string `json:"status"`
        Error  string  `json:"error"`
    }
err := errors.New("Total Price cannot be a negative value")
errRes := ErrorResponse{"ERROR", err.Error()}
response, errr := json.Marshal(errRes)
if errr != nil {
    log.Fatal(err)
    // you should write something to responseWriter w here before returning
    http.Error(w, "Internal server error", http.StatusInternalServerError)
    return
}
io.WriteString(w, string(response))
  

Обратите внимание, что в случае сбоя маршалинга вам все равно следует написать какой-то ответ перед возвратом.