Как лучше проверить JSON на стороне сервера
При обработке запросов POST, PUT и PATCH на стороне сервера нам часто нужно обрабатывать некоторые JSON для выполнения запросов.
Очевидно, что нам необходимо проверить эти JSON (например, структуру, допустимые/ожидаемые ключи и типы значений), и я вижу как минимум два способа:
-
После получения JSON подтвердите предварительный просмотр JSON, поскольку он, до, что-то с ним сделает, чтобы завершить запрос.
-
Возьмите JSON так, как он есть, начните его обрабатывать (например, получить доступ к его различным ключевым значениям) и попытаться проверить его на ходу при выполнении бизнес-логики и, возможно, использовать некоторые обработки исключений для обработки данных vogue.
1-й подход кажется более надежным по сравнению со вторым, но, вероятно, более дорогостоящим (по времени), потому что каждый запрос будет проверен (и, надеюсь, большинство из них действительны, поэтому проверка является излишней).
Второй подход может сохранить обязательную проверку правильных запросов, но смешивание проверок внутри бизнес-логики может быть ошибочным или даже рискованным.
Какое из двух выше лучше? Или, есть ли еще лучший способ?
Ответы
Ответ 1
То, что вы описываете с помощью POST, PUT и PATCH, похоже на то, что вы реализуете API REST. В зависимости от вашей базовой платформы вы можете использовать библиотеки, которые будут сопоставлять JSON с объектами, которые очень мощные, и выполняет эту проверку для вас. В JAVA вы можете использовать Jersey, Spring или Jackson. Если вы используете .NET, вы можете использовать Json.NET.
Если эффективность является вашей целью, и вы хотите проверить каждый запрос, было бы идеально, если бы вы могли оценить на интерфейсе, если используете JavaScript, вы можете использовать json2. JS.
Что касается сравнения ваших методов, вот список Pro/Cons.
Метод №1: по запросу
Pros
- Сохраняется целостность бизнес-логики. Как вы упомянули, попытка проверки правильности обработки бизнес-логики может привести к недействительным проверкам, которые могут быть действительно действительными и наоборот, или же проверка может непреднамеренно повлиять на бизнес-логику отрицательно.
- Как отметил Норберт, поймать ошибки перед рукой повысит эффективность. Логический вопрос, который возникает в этом вопросе, - это то, зачем тратить время на обработку, если есть ошибки в первую очередь?
- Код будет чище и легче читать. Разделение валидации и бизнес-логики приведет к более чистым, более легким для чтения и поддержки кода.
против
- Это может привести к избыточной обработке, что означает более длительное вычислительное время.
Метод # 2: проверка на Go
Pros
- Эффективно теоретически, экономя процесс и время вычисления, делая их одновременно.
против
- В действительности, время сохранения процесса, вероятно, незначительно (как упоминал Норберт). Вы все еще проверяете проверку в любом случае. Кроме того, время обработки теряется, если обнаружена ошибка.
- Целостность данных может быть включена. Возможно, JSON становится поврежденным при его обработке таким образом.
- Код не такой четкий. При чтении бизнес-логики может быть не так очевидно, что происходит, потому что логика проверки смешанна.
На самом деле это сводится к Точность против Скорость. Обычно они имеют обратную связь. По мере того, как вы становитесь более точными и подтвердите свой JSON, вам, возможно, придется идти на компромисс по скорости. Это действительно заметно только в больших наборах данных, поскольку в наши дни компьютеры очень быстрые. Это зависит от вас, чтобы решить, что более важно, учитывая точные данные, которые, по вашему мнению, могут иметь данные при его получении или важна ли эта дополнительная секунда или около того. В некоторых случаях это имеет значение (т.е. С фондовым рынком и приложениями здравоохранения, миллисекунды), и оба они очень важны. Именно в этих случаях, когда вы увеличиваете, например, точность, вам может потребоваться увеличить скорость, получив более высокую производительность.
Надеюсь, это поможет.
Ответ 2
Первый подход более надежный, но не должен быть заметно дороже. Это становится менее дорогостоящим, даже если вы можете прервать процесс синтаксического анализа из-за ошибок: ваша бизнес-логика обычно занимает > 90% ресурсов в процессе, поэтому, если у вас есть ошибка% 10%, вы уже являетесь нейтральным ресурсом, Если вы оптимизируете процесс проверки, чтобы проверки из бизнес-процесса выполнялись заранее, частота ошибок может быть намного ниже (например, 1 из 20 до 1 из 100), чтобы оставаться нейтральной.
В качестве примера реализации, предполагающей предварительную проверку данных, смотрите GSON (https://code.google.com/p/google-gson/):
GSON работает следующим образом: каждая часть JSON может быть передана в объект. Этот объект напечатан или содержит типизированные данные:
Пример объекта (JAVA используется в качестве примера):
public class someInnerDataFromJSON {
String name;
String address;
int housenumber;
String buildingType;
// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name=name; }
//etc.
}
Данные, обработанные GSON, используются с предоставленной моделью, уже проверенным типом.
Это первый момент, когда ваш код может прерваться.
После этой точки выхода, предполагая, что данные подтверждены моделью, вы можете проверить, находятся ли данные в определенных пределах. Вы также можете записать это в модель.
Предположим, что для этого buildingType является список:
- Отдельный семейный дом
- Многоквартирный дом
- квартира
Вы можете проверять данные во время разбора, создавая сеттер, который проверяет данные, или вы можете проверить его после разбора в первом наборе вашего бизнес-правила. Преимущество первой проверки данных в том, что ваш более поздний код будет иметь меньше обработки исключений, поэтому все меньше и легче понять код.
Ответ 3
В общем, первым вариантом будет путь. Единственная причина, почему вам, возможно, придется подумать о втором варианте, - это если вы имели дело с данными JSON, которые были десятками мегабайт больших или более.
Другими словами, только если вы пытаетесь передать JSON и обрабатывать его на лету, вам нужно подумать о втором варианте.
Предполагая, что вы имеете дело с несколькими сотнями КБ больше всего на JSON, вы можете просто перейти на вариант 1.
Вот несколько шагов, которые вы могли бы выполнить:
- Пойдите для парсера JSON, такого как GSON, который просто преобразует весь ваш
JSON вводится в соответствующий объект модели домена Java. (Если GSON
не генерирует исключение, вы можете быть уверены, что JSON
отлично действует.)
- Конечно, объекты, которые были построены с использованием GSON на шаге 1
может не находиться в функционально допустимом состоянии. Например, функциональный
проверки, такие как обязательные поля и лимитированные проверки, должны быть выполнены.
- Для этого вы можете определить метод validateState, который неоднократно
проверяет состояния самого объекта и его дочерних объектов.
Вот пример метода validateState
:
public void validateState(){
//Assume this validateState is part of Customer class.
if(age<12 || age>150)
throw new IllegalArgumentException("Age should be in the range 12 to 120");
if(age<18 && (guardianId==null || guardianId.trim().equals(""))
throw new IllegalArgumentException("Guardian id is mandatory for minors");
for(Account a:customer.getAccounts()){
a.validateState(); //Throws appropriate exceptions if any inconsistency in state
}
}
Ответ 4
Я бы окончательно пошел на проверку перед обработкой.
Скажем, вы получаете данные json
с переменными 10, которые вы ожидаете:
- первые 5 переменных будут иметь тип строка
- 6 и 7 должны быть целыми числами
- 8, 9 и 10 должны быть массивами
Вы можете выполнить быструю проверку типа переменной, прежде чем приступить к обработке любой из этих данных и вернуть ответ об ошибке проверки, если один из десяти не прошел.
foreach($data as $varName => $varValue){
$varType = gettype($varValue);
if(!$this->isTypeValid($varName, $varType)){
// return validation error
}
}
// continue processing
Подумайте о сценарии, в котором вы непосредственно обрабатываете данные, а затем 10-е значение оказывается недопустимым. Обработка предыдущих 9 переменных была пустой тратой ресурсов, так как вы в конечном итоге возвращаете какой-либо ответ об ошибке проверки. Кроме того, вам необходимо отменить любые изменения, которые уже сохраняются в вашем хранилище.
В моем примере я использую только тип переменной, но перед обработкой любого из них я предлагаю полную проверку (длину, максимальные/минимальные значения и т.д.) всех переменных.
Ответ 5
Ответ полностью зависит от вашего варианта использования.
Если вы ожидаете, что все вызовы возникнут у доверенных клиентов, тогда проверка правильности схемы должна быть реализована так, чтобы она активировалась только при установке флага отладки.
Однако, если ваш сервер предоставляет общедоступные службы api, вы должны проверить правильность входящих вызовов. Это не просто проблема с производительностью - ваш сервер, скорее всего, будет тщательно изучен для уязвимостей безопасности ваших клиентов, хакеров, конкурентов и т.д.
Если ваш сервер предоставляет частные службы api нескольким клиентам (например, в закрытой сети, где он должен интегрироваться с системами сторонних разработчиков), вы должны, по крайней мере, выполнить предварительные проверки, которые сохранят вас обвиняя кого-то в других.
Ответ 6
Это действительно зависит от ваших требований. Но в целом я всегда ходил за # 1.
Несколько соображений:
Для согласованности я бы использовал метод # 1, для производительности # 2. Однако при использовании # 2 вы должны учитывать, что откат в случае недействительного ввода может осложниться в будущем, по мере изменения логики.
Проверка Json не должна длиться так долго. В python вы можете использовать ujson для синтаксического разбора json-строк, который является сверхбыстрой реализацией C-модуля json.
Для проверки я использую модуль python jsonschema, который упрощает проверку json.
Другой подход:
если вы используете jsonschema, вы можете проверить запрос json по шагам. Я бы выполнил первоначальную проверку наиболее распространенных/важных частей структуры json и проверил оставшиеся части по пути бизнес-логики. Это позволило бы писать более простые json-схемы и, следовательно, более легкий.
Окончательное решение:
Если (и только если) это решение имеет решающее значение, я бы использовал оба решения, их временные профили в правильном и неправильном состоянии ввода и взвешивал результаты в зависимости от неправильной входной частоты. Поэтому: