Как настроить ответы HTTP 400 для ошибок синтаксического анализа?

Я написал службу REST API, которая требует, чтобы все ответы были в формате JSON. Однако, когда парсер Go HTTP-запроса обнаруживает ошибку, он возвращает 400 в виде обычного текстового ответа, даже не вызывая мои обработчики. Пример:

> curl -i -H 'Authorization: Basic hi    
there' 'http://localhost:8080/test' -v
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Authorization: Basic hi
> there
> 
< HTTP/1.1 400 Bad Request
HTTP/1.1 400 Bad Request
< Content-Type: text/plain; charset=utf-8
Content-Type: text/plain; charset=utf-8
< Connection: close
Connection: close

< 
* Closing connection 0

Обратите внимание на недопустимый заголовок авторизации. Конечно, 400 — это правильный ответ, но, конечно же, текстовый/обычный. Есть ли способ настроить синтаксический анализатор Go http для использования пользовательских типов и тел ответов на ошибки?


person theory    schedule 21.08.2017    source источник
comment
Вы используете какой-то фреймворк? Я никогда не видел такого поведения с обработчиком stdlib http.   -  person Adrian    schedule 21.08.2017
comment
Неа. вот глупый простой пример.   -  person theory    schedule 21.08.2017


Ответы (2)


Вы не можете. Вы можете найти это в источнике net/http, это происходит только в том случае, если запрос был искажен:

https://github.com/golang/go/blob/master/src/net/http/server.go#L1744

Я думаю, что ваша проблема может заключаться в новой строке в заголовке, которую вы добавляете в curl?

На ошибки 401, 403, 404, 500 вы сможете ответить с помощью json, но неверные запросы или неверные заголовки (слишком длинные, искаженные) обрабатываются в server.go.

В настоящее время нет способа перехватить такие ошибки, хотя он находится на рассмотрении, так что ваш единственный решение на ходу было бы исправить исходный код stdlib (я не рекомендую это). Однако, поскольку эта ошибка появляется только в том случае, если клиент допустил ошибку и запрос искажен, это, вероятно, не является большой проблемой. Причина текстового ответа в том, что браузер или аналогичный клиент (например, curl без -v) не просто увидит пустой ответ. Вы можете поместить прокси-сервер, такой как nginx, перед своим приложением, но тогда вы никогда не увидите запрос, так как это плохой запрос, ваш прокси-сервер обработает его.

Возможно, вы сможете сделать это с помощью прокси-сервера, такого как nginx, если вы установите конкретную статическую страницу ошибок, чтобы она обслуживала 400 ошибок и обслуживала указанный вами файл 400.json? Это единственное решение, которое я могу придумать. Для nginx может работать такая директива:

error_page 400 /400.json;

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

person Kenny Grant    schedule 21.08.2017
comment
Я боялся, что это будет ответ. Да, новая строка - это ошибка. Нет, это не большая проблема, за исключением того, что мне придется документировать API, так как он всегда возвращает JSON, если только Go https не вернет ошибку до того, как мой код увидит запрос. Я ценю желание включить тело в ответ (хотя в этом мало деталей; мне потребовалось некоторое время, чтобы найти ошибку), но в идеале я мог бы каким-то образом контролировать тип контента и содержание всех ответов. Прокомментирую проблему, спасибо! - person theory; 21.08.2017

Если вы используете стандартную библиотеку net/http, вы можете использовать следующий код. Взгляните на этот ответ https://stackoverflow.com/questions/9996767/showing-custom-404-error-page-with-standard-http-package, из которого я получил этот пример

func homeHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        errorHandler(w, r, http.StatusNotFound)
        return
    }
    fmt.Fprint(w, "welcome home")
}

func errorHandler(w http.ResponseWriter, r *http.Request, status int) {
    w.WriteHeader(status)
    if status == http.StatusNotFound {
        // JSON Out here
    }
}
person Varcorb    schedule 21.08.2017
comment
400 и 404 не одно и то же. Пожалуйста, прочитайте вопрос. - person Adrian; 21.08.2017