如何使用SYNCHRONOUS页面POST从HTML表单发送复杂的JSON对象?
我的服务器正在使用ServiceStack,并希望收到一些这样的数据:
{ Customer: { Company: "TheCompany", RegionCode: "AU_NSW" }, Name: { First: "Jimi", Last: "Hendrix" } }
我有一个包含这些字段的表单,我可以使用JQuery轻松获取数据,创建嵌套的JSON对象并使用$ .post发送它。
但我不想将其作为AJAX发送,因为我希望整个页面都提交,然后浏览器将服务器的响应显示为新页面。 只是经典的forms发布行为。
我已经尝试将复杂的json作为字符串嵌入隐藏的表单字段中 – 没有雪茄。
我还查看了ServiceStack是否有任何命名约定,以便我可以调用我的表单字段“Name [First]”并让ServiceStack将正确的值放在正确的嵌套结构中 – 也就是没有雪茄。
- 有没有办法可以在表单发送数据之前将JSON对象附加到表单的POST数据? 要么
- 有没有办法我可以使用jQuery进行整页提交(所以我可以发送一个复杂的嵌套JSON,同时仍然有正常的“页面提交”行为)?
虽然Mythz建议发布JSV值会起作用,但在JavaScript中构建和维护复杂的JSV有时会很麻烦。 例如,您可能必须处理转义用户输入的数据,并且语法问题可能难以跟踪
这个解决方案看起来很复杂,但实际上并非如此,并且高度可重用,只需要您可以发送编码的JSON,jQuery非常容易。
完整的演示源代码在这里
流程 – 工作原理:
- 您的jQuery使用提交时的表单数据创建DTO
- DTO编码为JSON,只需使用
JSON.stringify(data)
- JSON以隐藏forms发送,作为
Data
字段的值 - 服务器DTO属性filter将
Data
字段的JSON值反序列化到DTO中 - 您的服务会看到正常填充的DTO。
过滤属性:
我的解决方案将表单邮件中编码为JSON的DTO对象发送到服务。 然后,一个简单的filter拦截请求并从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):
- 获取您的表单值
- 将所需的DTO结构构建为JavaScript对象
- 将该DTO转换为JSON字符串
- 将隐藏的表单值设置为DTO字符串并提交
$("#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
与应接收有效负载的属性的属性相匹配
ServiceStack可以使用JSV格式POST复杂类型 ,例如:
否则,您可以使用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保持平稳,例如:
然后您可以使用x-www-form-urlencoded
Content-Type进行POST操作,或使用ServiceStack的ss-utils.js bindForm方法进行ajaxify ,例如:
$("#theForm").bindForm();
将提交处理程序附加到表单,该表单将JSON作为表单中预先创建的隐藏输入字段的值。
$(form_to_submit).on('submit', function() { $(form_to_submit).find(hidden_input).val(json_value); });
要使用jQuery提交表单,请使用:
$(form_to_submit).submit();
我在这里遇到了同样的问题,我在使用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。