如何使用SYNCHRONOUS页面POST从HTML表单发送复杂的JSON对象?

时间:2014-04-29 03:38:24

标签: javascript jquery json servicestack

我的服务器正在使用ServiceStack,并希望收到一些这样的数据:

{
    Customer: {
        Company: "TheCompany",
        RegionCode: "AU_NSW"
    },
    Name: {
        First: "Jimi",
        Last: "Hendrix"
    }

}

我有一个包含这些字段的表单,我可以使用JQuery轻松获取数据,创建嵌套的JSON对象并使用$ .post发送它。

但我不想将其作为AJAX发送,因为我希望整个页面都提交,然后浏览器将服务器的响应显示为新页面。只是经典的表单帖子行为。

我尝试将复杂的json作为字符串嵌入隐藏的表单字段中 - 没有雪茄。

我还查看了ServiceStack是否有任何命名约定,以便我可以调用我的表单字段“Name [First]”并让ServiceStack将正确的值放在正确的嵌套结构中 - 也就是没有雪茄。

  1. 有没有办法可以在表单发送数据之前将JSON对象附加到表单的POST数据? 或
  2. 有没有办法可以使用jQuery进行整页提交(所以我可以发送一个复杂的嵌套JSON,同时仍然有正常的“页面提交”行为)?

4 个答案:

答案 0 :(得分:6)

虽然Mythz建议发布JSV值会起作用,但在JavaScript中构建和维护复杂的JSV有时会很麻烦。 例如,您可能必须处理转义用户输入的数据,并且语法问题可能难以跟踪

这个解决方案看起来很复杂,但实际上并非如此,并且具有高度可重用性,只需要您可以发送编码的JSON,而jQuery非常容易。

Full Demo Source Code Here

流程 - 工作原理:

  1. 您的jQuery使用提交
  2. 上的表单数据创建DTO
  3. DTO编码为JSON,只需使用JSON.stringify(data)
  4. JSON以隐藏形式发送,作为Data field
  5. 的值
  6. 服务器DTO属性过滤器将Data字段的JSON值反序列化到您的DTO中
  7. 您的服务会看到正常填充的DTO。
  8. 过滤器属性:

    我的解决方案将表单帖子中编码为JSON的DTO对象发送到服务。然后,一个简单的过滤器拦截请求并从JSON有效负载填充DTO。

    public class GetFromJsonVariableAttribute : Attribute, IHasRequestFilter
    {
        string _variableName;
    
        public GetFromJsonVariableAttribute(string variableName = "Data")
        {
            _variableName = variableName;
        }
    
        public void RequestFilter(IRequest req, IResponse res, object requestDto)
        {
            // Convert the JSON payload to DTO format
            var payload = req.GetParam(_variableName);
            if(payload != null)
                requestDto = JsonSerializer.DeserializeFromString(payload, requestDto.GetType());
        }
    
        public int Priority { get { return int.MinValue; } }
        IHasRequestFilter IHasRequestFilter.Copy() { return this; }
    }
    

    用法

    然后使用您只需将属性添加到您的DTO。 Data是将保存JSON有效内容的表单变量的名称。您可以在此处选择任何您想要的名称。

    [GetFromJsonVariable("Data")]
    [Route("/Customers","POST")]
    public class CreateCustomerRequest : IReturnVoid
    {
        public Customer Customer { get; set; }
        public Name Name { get; set; }
    }
    

    客户端(jQuery):

    1. 获取您的表单值
    2. 将所需的DTO结构构建为JavaScript对象
    3. 将该DTO转换为JSON字符串
    4. 将隐藏的表单值设置为DTO字符串&提交
    5. $("#CreateCustomer").on("submit", function(){
      
          // Get the form values into simple key value array
          var values = {};
          $.each($(this).serializeArray(), function(){ values[this.name] = this.value; });
      
          // Prepare the DTO
          var data = {
              Customer: {
                  Company: values["Company"],
                  RegionCode: values["RegionCode"]
              },
              Name: {
                  First: values["First"],
                  Last: values["Last"]
              }
          };
      
          // Convert it to JSON
          $('#PayloadForm [name="Data"]').val(JSON.stringify(data));
          $('#PayloadForm').submit();
          return false;
      });
      

      使用HTML创建用户将与之交互的表单,不执行任何操作,但链接到jQuery提交事件代码;以及一个实际执行同步POST的隐藏表单。 请注意,属性Data与应在上接收有效负载的属性相匹配

      <form id="CreateCustomer">
          <input type="text" name="Company" value="TheCompany" /><br/>
          <input type="text" name="RegionCode" value="AU_NSW" /><br/>
          <input type="text" name="First" value="Jimi" /><br/>
          <input type="text" name="Last" value="Hendrix" /><br/>
          <input type="submit" value="Submit" />
      </form>
      
      <!-- This form is hidden -->
      <form action="/Customers" method="POST" id="PayloadForm">
          <input type="hidden" name="Data" value="">
      </form>
      

答案 1 :(得分:1)

ServiceStack可以POST complex types using the JSV Format,例如:

<input name="Customer" value="{Company:TheCompany,RegionCode:AU_NSW}" />
<input name="Name" value="{First:Jimi,Last:Hendrix}" />

否则,您可以使用JSON发送复杂类型,例如使用jQuery的$ .ajax:

$.ajax({ 
   type: 'POST',
   contentType: 'application/json; charset=utf-8',
   url: "http://host/myservice",
   dataType: 'json',
   data: JSON.stringify({Customer:{Company:'x',RegionCode:'x'}}),
   success: function(response){ ... }
});

尽管为了实现最大的互操作性,您应该努力使您的请求DTO保持不变,例如:

<form id="theForm" ...>
  <input name="Company" value="TheCompany" />
  <input name="RegionCode" value="AU_NSW" />
  <input name="FirstName" value="Jimi" />
  <input name="LastName" value="Hendrix" />
</form>

然后您可以按原样使用x-www-form-urlencoded Content-Type进行POST,或使用ServiceStack's ss-utils.js bindForm method进行ajaxify,例如:

$("#theForm").bindForm();

答案 2 :(得分:0)

将一个提交处理程序附加到表单,该表单将JSON作为表单中预先创建的隐藏输入字段的值。

$(form_to_submit).on('submit', function() {
    $(form_to_submit).find(hidden_input).val(json_value);
});

使用jQuery提交表单:

$(form_to_submit).submit();

答案 3 :(得分:0)

我在这里遇到了同样的问题,我在使用NodeJS和Express Server。我想发布一个复杂的JSON对象,我已经构建为用户选择的客户端。然后我将onClick事件附加到一个调用我的SubmitForm函数的按钮。

您的数据可以是任何JSON对象。请务必解析服务器端。

function Param(name, value){
    var hiddenField = document.createElement('input');
    hiddenField.setAttribute('type', 'hidden');
    hiddenField.setAttribute('name', name);
    hiddenField.setAttribute('value', value);
    return hiddenField;
}

function SubmitForm(data){
    var form = document.createElement('form');
    form.setAttribute('method', 'post');
    form.setAttribute('action', '/route');
    form.appendChild(Param('data', JSON.stringify(data)));

    document.body.appendChild(form);
    form.submit();    
}

此外,这是纯粹的JavaScript。对于那些喜欢消除开销的人来说,这里没有隐藏的HTML或jQuery。