#c# #asp.net #asp.net-mvc #validation
#c# #asp.net #asp.net-mvc #проверка
Вопрос:
Мы создаем веб-приложение, и у нас возникла некоторая проблема с отображением сообщений об ошибках проверки на стороне сервера во внешнем интерфейсе.
Чтобы дать некоторый контекст, мы запускаем одностраничное приложение, интерфейс которого реализован в react.js и внутренний api в asp.net . В нашем приложении есть несколько форм, которые мы просим пользователей заполнить, и мы планируем реализовать проверку формы как на стороне клиента, так и на стороне сервера.
Рабочий процесс, который мы имеем сейчас, заключается в том, чтобы сначала выполнить проверку на стороне клиента, а затем передать данные в серверный api. Тогда серверная часть сначала выполнила бы ту же проверку, что и интерфейс, чтобы убедиться, что запрос не исходит от злоумышленника, который обошел правила проверки на стороне клиента. Для запроса, который поступает из обычного канала, он никогда не должен завершаться неудачей на этом этапе, и если это происходит, однако, это просто означает, что мы имеем дело с хакером.
Однако при проверке на стороне сервера их немного больше. Есть информация, о которой клиентская сторона не знает, например, существует ли в нашей базе данных только что введенный пользователем банковский счет? (у нас нет специального API для проверки этого, поэтому мы должны сделать это на уровне формы после того, как пользователь отправил всю форму на сторону сервера).
Итак, в заключение, правила проверки на стороне сервера состоят из двух частей: базовых правил проверки, которые совместно используются с интерфейсом, и расширенных правил проверки, для которых требуется доступ к базе данных, которая доступна только на стороне сервера.
Теперь вопрос в том, как мы сообщаем пользователю после того, как они не выполнили эти два типа проверок?
Ниже приведены два предложения, к которым мы пришли на данный момент
Решение 1: используйте HTTP 400 — Bad Request для обозначения сбоя в работе
мы обрабатываем эти два типа проверки на стороне сервера одинаково, и когда какой-либо запрос завершается с ошибкой, мы отправляем обратно HTTP 400 с объектом json, содержащим подробные сообщения об ошибках, объясняющие причину сбоя. Пример ответа будет
HTTP 400 Bad Request
{
"bsb_name" :"bsb_name has special characters",
"bsb_number":"bsb number doesn't exist",
"amount":"amount is required"
}
Теперь проблема в том, что мы не единственная сторона, которая может вернуть HTTP 400. Поскольку мы используем asp.net фреймворк плюс OWIN framework, сами фреймворки также могут отправлять обратно HTTP 400 при определенных обстоятельствах, и HTTP 400, который они отправляют, сильно отличается от нашего. Это создает дополнительную работу для интерфейса, чтобы различать 2 типа HTTP 400 и обрабатывать их по-разному.
Было внесено предложение пересмотреть наш ответ, и вместо отправки объекта JSON мы отправляем обратно обычную строку — исходя из предположения, что asp.net framework / owin отправил бы обратно свой HTTP 400 в простой строке (1). Таким образом, во внешнем интерфейсе нам не нужно их различать, и мы можем обрабатывать их оба одинаково. Кроме того, чтобы избежать введения магических разделителей, мы возвращаем только текст первого сообщения об ошибке, а не все из них. Итак, пример ответа может быть
HTTP 400 Bad Request
"Bank account name has special characters"
и мы собираемся обработать его так же, как HTTP 400, возвращенный asp.net фреймворк, скажем,
HTTP 400 Bad Request
Request header too long
So in both cases, a site user would see an error message after submitting their form saying «Bank account name has special characters» or «Request header too long»
solution 2 : Use Business Protocol rather HTTP Protocol
If the request fails the basic server side validation, which can only happen for hackers, server would throw exception immediately which would end up with a HTTP 500. Once receiving the HTTP 500, client side would simply direct user to a general error page saying something unexpected happened without any detailed information — we try to avoid being hacking friendly.
Однако, если запрос не проходит расширенную проверку на стороне сервера, что может произойти с обычным пользователем приложения, сервер все равно вернет HTTP 200 — Success, но с другим status_code, обозначающим, что это ответ об ошибке. например
HTTP 200 Success
{
status_code: Err_123
error_message: "bsb doesn't exist"
}
Я лично хочу использовать решение 2, но мне сказали, что мы не должны использовать HTTP 200 для ошибки проверки. Поскольку HTTP 200 означает OK, использование HTTP 200 в случае сбоя проверки на стороне сервера не имеет смысла.
Насколько я понимаю, код состояния HTTP предназначен для протокола HTTP и не должен иметь ничего общего с вашей бизнес-логикой. HTTP 200 означает только, что клиент отправил запрос на сервер, и сервер успешно обработал его, вернув ответ. Означает ли ответ, что транзакция была одобрена, или транзакция была отклонена, или отправленный вами BSB_Number не существует, это просто не имеет значения. И это не должно волновать.
Таким образом, в случае, когда транзакция действительно отклоняется или форма содержит неверные входные данные, которые могут быть обнаружены только на стороне сервера, мы все равно должны ответить HTTP 200, но назначить другой status_code, который эквивалентен HTTP 400, НО это в нашем бизнес-протоколе. Таким образом, мы должны эффективно отличать наш бизнес-протокол от протокола http, и мы не можем использовать HTTP FAILURE для обозначения бизнес-СБОЯ (2).
Выше приведены все мои мысли по этому поводу, и я приветствую все комментарии, дальнейшее обсуждение этой темы.
Приветствую, Бо
-
(1): предположение неверно, поскольку я недавно узнал, что IIS может возвращать HTTP 400 при некоторых обстоятельствах. Когда это происходит, возвращается HTML-страница.
-
(2): Аналогией может быть
**IP -- TCP -- HTTP -- BUSINESS**
If TCP layer fails, IP shouldn't be concerned;
If HTTP layer fails, TCP shouldn't be concerned;
If BUSINESS layer fails, HTTP shouldn't be concerned;
Разве «отдельная проблема» не является здравым смыслом в программировании?? Я немного удивлен, когда вижу, что кто-то говорит «можно вернуть HTTP 400 в случае сбоя в работе»
Комментарии:
1. Лично я считаю, что вам следует использовать business protocol. Ошибки протокола HTTP указывают именно на это, когда это не то, что сгенерировало исключение.
Ответ №1:
На мой взгляд, разделение проблем должно быть первым и первостепенным.
Решение первое, хотя указано, что ошибка возникает на бизнес-уровне, подразумевает, что ошибка в представлении. Теперь неясно, откуда на самом деле возникает ошибка.
С другой стороны, в решении 2 подробно указано, что HTTP-транзакция прошла успешно и что бизнес-логика ответила ошибкой.
В идеале (на мой взгляд) все ошибки на стороне сервера должны улавливаться и сообщаться как ошибка в бизнес-логике, чтобы ошибки HTTP выдавались только тогда, когда пользователь запрашивает плохую или конфиденциальную страницу.
Это приводит к более изящному сбою системы и делает ее более масштабируемой. (Например, если вы реализуете свой API в другом месте, вам не нужно включать в него обработку ошибок HTTP, только отображение указанной ошибки)
Кроме того, это могло бы лучше подойти для P.SE и не ТАК.
Комментарии:
1. Это хороший ответ, поскольку он делает ваше решение переносимым по различным протоколам и устройствам. Хотя вы всегда можете использовать HTTP сейчас, в будущем это может оказаться не так. Даже если вы никогда не планируете переходить с HTTP, это хороший ответ исключительно потому, что он проводит очевидное различие между исключением HTTP и исключением бизнес-логики.
Ответ №2:
Мое решение похоже на решение 2. Я определяю объект как ответ на все запросы RESTful.
class Entity<T>{
public int code {get;set;}
public int message {get;set;}
public T content {get;set;}
}
Независимо от того, будет ли запрос выполнен успешно или с ошибкой, интерфейс получит объект и проверит код. Если код равен 200 (или другим определенным), продолжайте обработку содержимого, в противном случае отобразите сообщение и вернитесь.
Ответ №3:
Для запроса, который поступает из обычного канала, он никогда не должен завершаться неудачей на этом этапе, и если это происходит, однако, это просто означает, что мы имеем дело с хакером.
если ваш API общедоступен, почему бы не использовать код состояния 500,…Это способ обмануть людей, пытающихся получить доступ к вашему API. Но, вы теперь, если это не внутренняя ошибка сервера с сообщением о состоянии чтения. Или вы используете код состояния 202 (Запрос принят для обработки, но обработка не завершена. В конечном итоге запрос может быть обработан, а может и не быть выполнен, поскольку он может быть запрещен при фактической обработке. нет возможности для возврата статуса из асинхронных операций, подобных этой.)
если вы используете код состояния 200 или 400, и каждый орган должен знать, можно ли это ввести … но, на ваше усмотрение, это всего лишь мое предложение, как то, что вам нужно мнение.
Ответ №4:
На мой взгляд, ваш код ответа 400 в порядке. На самом деле вам нужно смоделировать, как вы должны реагировать на сценарии проверки. Например, BaseResponse.cs будет выглядеть примерно так.
public class BaseResponse<T> where T: object {
public T Data {get;set;}
public bool Success {get; set;}
public IList<Error> Errors {get;set;}
}
С другой стороны, вы можете определить класс ошибки следующим образом
public class Error {
string Type {get;set;} // "validation", "business"
string Code {get;set;} // "VAL_1234", "BIZ_4321"
string Message {get;set;} // "Value should be greater than 10"
}
Теперь на стороне Javascript в приложении react ваш код не такой сложный
fetch(url)
.then((response)=> {
if(response.status === 400) {
let json = response.json();
if(json) { // you have validation errors, do something with errors property in json
}else { // 400 was returned because of some other reason
}
}
});
Должно сработать более сложное решение в сочетании с тем, что у меня есть выше. Пример здесь
Комментарии:
1. вы позволяете json = response.json() выдаст исключение, когда iis.net/learn/troubleshoot/diagnosing-http-errors / …
2. Мой код приведен только для иллюстрации. В случае исключения вы можете обработать его по-другому. В основном нужно проверить, имеет ли ответ тело или нет.
3. HTTP 400 может поступать с вашего веб-хостинга (т. е. IIS, apache или Nginx), может поступать из веб-фреймворка (asp.net, flusk, rails ..), или может быть из вашего кода. Невозможно определить, откуда оно взялось, поскольку вы не знаете iis, apache, nginx, asp.net , flusk, rails форматируют свой HTTP 400. Причина, по которой нам нужно их различать, заключается в том, что мы можем корректно обработать ошибку, возвращаемую нашим серверным кодом, поскольку мы знаем, что это такое; но я понятия не имею, как обрабатывать HTT 400, возвращаемый IIS, скажем, мы можем только разрешить ему перейти на страницу общей ошибки, если это произойдет.
4. Тело ответа @BoChen IIS 400 отличается от того, что задает ваше приложение. В javascript вы можете проверить ответ json, чтобы определить, создан ли его сервер или приложение.