【问题标题】:How to validate JSON object?如何验证 JSON 对象?
【发布时间】:2011-07-03 06:48:33
【问题描述】:

我想在服务器端验证传入的 json 对象的正确性。是否有标准/最佳方式来做到这一点?您的验证方法是什么?

【问题讨论】:

  • 您使用什么服务器端语言?很大程度上取决于此。

标签: java json validation


【解决方案1】:

我可以从您的 cmets 得出结论,您首先要确保 json 对象有效,如果有效,则可以创建 java 对象。无论您的论点是什么,validol 库都允许您以声明方式声明复杂的验证规则,如果成功,则会生成一个 java 对象。

假设您有一个订单注册请求,它由几个块组成,包括payment。为简洁起见,我省略了除此之外的所有块。在这种情况下,此请求如下所示:

{
    "payment":{
        "expires_at":"12/29",
        "card_number":12345612341234
    }
}

这是一个验证码:

/*1 */    public class ValidatedRegistrationRequest implements Validatable<RegistrationRequest>
          {
              private String jsonRequestString;
              private Connection dbConnection;

/*6 */        public ValidatedRegistrationRequest(String jsonRequestString, Connection dbConnection)
              {
                  this.jsonRequestString = jsonRequestString;
                  this.dbConnection = dbConnection;
              }

              @Override
/*13*/        public Result<RegistrationRequest> result() throws Exception
              {
                  return
/*16*/                new FastFail<>(
/*17*/                    new WellFormedJson(
/*18*/                        new Unnamed<>(Either.right(new Present<>(this.jsonRequestString)))
                          ),
/*20*/                    requestJsonObject ->
/*21*/                        new UnnamedBlocOfNameds<>(
/*22*/                            List.of(
/*23*/                                new FastFail<>(
/*24*/                                    new IsJsonObject(
/*25*/                                        new Required(
/*26*/                                            new IndexedValue("payment", requestJsonObject)
                                              )
                                          ),
/*29*/                                    paymentJsonObject ->
/*30*/                                        new NamedBlocOfNameds<>(
/*31*/                                            "payment",
/*32*/                                            List.of(
/*33*/                                                new CardIsNotExpired(
/*34*/                                                    new AsString(
/*35*/                                                        new Required(
/*36*/                                                            new IndexedValue("expires_at", paymentJsonObject)
                                                              )
                                                          )
                                                      ),
/*40*/                                                new CardNumberIsNotBlacklisted(
/*41*/                                                    new CardNumberSatisfiesLuhnAlgorithm(
/*42*/                                                        new Required(
/*43*/                                                            new IndexedValue("card_number", paymentJsonObject)
                                                              )
                                                          ),
/*46*/                                                    this.dbConnection
                                                      )
                                                  ),
/*49*/                                            Payment.class
                                              )
                                      )
                                  ),
/*53*/                            RegistrationRequest.class
                              )
                      )
                          .result();
              }
          }

让我们逐行看看这里发生了什么:

Line 1ValidatedRegistrationRequest 的声明。
Line 6 其构造函数接受尚未解析的 json 字符串。它可能来自传入的请求、收到的响应或几乎任何其他地方。
Line 13:调用此方法时开始验证。
Line 16:更高级别的验证对象是@987654332 @ 堵塞。如果第一个参数无效,则立即返回错误。
Lines 17-19: 检查 json 是否格式正确。如果是后者,验证会很快失败并返回相应的错误。
Line 20: 如果 json 格式正确,则调用闭包,并将 json 数据作为其单个参数传递。
Line 21: json数据得到验证。它的结构是命名块的未命名块。它对应一个 JSON 对象。
Line 26:第一个(也是唯一的)块称为 payment。
Line 25:它是必需的。
Line 24:它必须是一个 json对象。
Line 23:如果不是,将立即返回错误,因为它是FailFast 对象。
Line 29:否则,将调用闭包。
Line 30:付款块是由其他命名条目(对象或标量)组成的命名块。
Line 36:第一个称为 expires_at
Line 35:它是必需的。
Line 34:并表示为字符串,如果可能的话。如果没有,则返回错误。
Line 33:最后,检查它是否过期。
Line 43:第二个参数称为card_number。
Line 42:也是必需的.
Line 41: 必须满足 Luhn 算法。
Line 40: 并且不应该在我们的数据库中列入黑名单,因此...
Line 46: ... this.dbConnection 参数。
@ 987654356@:如果之前的所有验证检查都成功,则创建Payment 类的对象。
Line 53:最后,创建并返回RegistrationRequest。

验证成功后调用代码如下所示:

Result<RegistrationRequest> result = new ValidatedRegistrationRequest(jsonRequestString).result();
result.isSuccessful();
result.value().raw().payment().cardNumber(); // 12345612341234

您可以了解有关declarative validation 方法的更多信息,或立即前往quick start 条目以获取更多示例。

【讨论】:

    【解决方案2】:

    我的建议 - 反序列化 JSON 并查看它是否损坏。例如,如果您在服务器端使用 C#,则可以使用新奇的 DataContractJsonSerializer,或者使用旧方法使用 JavaScriptSerializer,这可以说要简单得多。

    var serializer = new JavaScriptSerializer();
    var result = serializer.Deserialize<Dictionary<string, object>>(jsonString);
    

    编辑:既然您使用的是 Java,那么我的 C# 示例当然不适用于您,但概念是相同的。 Stackoverflow 已经有了一些答案here: Convert a JSON string to object in Java ME?

    【讨论】:

    • 感谢您的回复。我知道将 json 转换为 java 对象的方法。在将其转换为 java 对象之前,我想对其进行快速通用验证(以检查其是否有效)。
    • @Harsha 验证 JSON 文本意味着在某种程度上解析它。因此,对于正确的 json 文本(在任何体面的应用程序中,它的数量应该比无效的 json 多很多),您最终将进行双重解析。这真的值得吗?
    • 很多时候,您可能希望在请求到达后端之前进行验证。在这种情况下,需要进行某种模式验证。
    【解决方案3】:

    使用 JSON 库对其进行解码。如果它使用遵循规范的库成功解码,则它是有效的。

    【讨论】:

    • 是的,最快的方法之一是将其解码为 java 对象,看看它是否在解码时抛出错误。我想对给定的 json 对象进行通用验证,而不将其转换为 java 对象。我不想仅仅为了验证而创建 java 对象。你最喜欢的 json 库/实用程序有什么可以帮助我的吗?
    猜你喜欢
    • 2021-05-18
    • 2017-10-20
    • 2015-11-09
    • 2017-10-15
    • 2015-10-24
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多