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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23355017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 00:45:29  来源:igfitidea点击:

How do I send a complex JSON object from an HTML form using SYNCHRONOUS page POST?

javascriptjqueryjsonservicestack

提问by McNulty

My server is using ServiceStack and would like to receive some data like this:

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

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

}

I have a form which has these fields and I can easily grab the data using JQuery, make the nested JSON object and use $.post to send it through.

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

But I don't want to send it as AJAX, because I want the entire page to submit and then the browser to show the server's response as a new page. Just classic form post behaviour.

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

I have tried embedding the complex json as strings inside hidden form fields - No cigar.

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

I have also looked to see if ServiceStack has any naming conventions such that I could call my form fields "Name[First]" and have ServiceStack put the right values in their correct nested structure - no cigar on that either.

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

  1. Is there a way I can attach a JSON object to a form's POST data just before that form sends the data through? or
  2. Is there a way I can do a full page submission with jQuery (so I can send a complex nested JSON whilst still having the normal "page-submit" behaviour)?
  1. 有没有一种方法可以在表单发送数据之前将 JSON 对象附加到表单的 POST 数据?或者
  2. 有没有一种方法可以使用 jQuery 进行整页提交(这样我就可以发送复杂的嵌套 JSON,同时仍然具有正常的“页面提交”行为)?

回答by Scott

While Mythz suggestion of posting JSV values would work, it can sometimes be cumbersome to build and maintain complex JSV in JavaScript. For example, you may have to deal with escaping user inputted data, and syntax issues can be hard to track

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

This solution looks complex but it's really not, and is highly re-usable and only requires that you can send encoded JSON, which from jQuery is very easy.

这个解决方案看起来很复杂,但实际上并不复杂,并且高度可重用,只需要您可以发送编码的 JSON,这在 jQuery 中非常简单。

Full Demo Source Code Here

完整的演示源代码在这里

Process - How it works:

过程 - 工作原理:

  1. Your jQuery creates the DTO using the form data on submit
  2. The DTO is encoded as JSON, simply using JSON.stringify(data)
  3. The JSON is sent in a hidden form as the value of Datafield
  4. A server DTO attribute filter deserializes the JSON value of Datafield into your DTO
  5. Your service see the DTO populated as normal.
  1. 您的 jQuery 使用提交时的表单数据创建 DTO
  2. DTO 被编码为 JSON,只需使用 JSON.stringify(data)
  3. JSON 以隐藏形式作为Data字段的值发送
  4. 服务器 DTO 属性过滤器将Data字段的 JSON 值反序列化为您的 DTO
  5. 您的服务会看到 DTO 正常填充。

Filter Attribute:

过滤器属性:

My solution sends the DTO object encoded as JSON in a form post to the service. Then a simple filter intercepts the request and populates the DTO from the JSON payload.

我的解决方案在表单发布中将编码为 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; }
}

Usage

用法

Then to use you simply add the attribute to your DTO. Datais the name of the form variable that will hold the JSON payload. You can choose any name you want here.

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

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

Client Side (jQuery):

客户端(jQuery):

  1. Get your form values
  2. Build the required DTO structure as a JavaScript object
  3. Convert that DTO to a JSON string
  4. Set your hidden form value to the DTO string & submit
  1. 获取表单值
  2. 将所需的 DTO 结构构建为 JavaScript 对象
  3. 将该 DTO 转换为 JSON 字符串
  4. 将隐藏的表单值设置为 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;
});

With the HTML create the form your user will interact with, with no action, but is linked to the jQuery submit event code; And a hidden form that will actually perform the synchronous POST. Note the attribute Datamatches that of the attribute the payload should be received on

使用 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>

回答by mythz

ServiceStack can POST complex types using the JSV Format, e.g:

ServiceStack 可以使用 JSV 格式 POST 复杂类型,例如:

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

Otherwise you can send complex types using JSON, e.g. with jQuery's $.ajax:

否则,您可以使用 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){ ... }
});

Although for maximum interoperability you should strive to keep your Request DTO's flat, e.g:

尽管为了最大程度的互操作性,您应该努力使请求 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>

Which you can then POST as-is which the browser will do using the x-www-form-urlencodedContent-Type, or even ajaxify using ServiceStack's ss-utils.js bindForm method, e.g:

然后您可以按原样 POST 浏览器将使用x-www-form-urlencodedContent-Type 执行的操作,甚至可以使用ServiceStack 的 ss-utils.js bindForm 方法进行 ajaxify,例如:

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

回答by sahbeewah

Attach a submit handler to the form which places the JSON as the value of a pre-created hidden input field within the form.

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

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

To submit a form using jQuery you use:

要使用 jQuery 提交表单,请使用:

$(form_to_submit).submit();

回答by dbarth

I ran into the same thing here where I was using NodeJS and an Express Server. I wanted to post a complex JSON object that I had built as the user made selections client side. I then attached an onClick event to a button that called my SubmitForm function.

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

Your data can be any JSON object. Just be sure to parse it server side.

您的数据可以是任何 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();    
}

Additionally, this is pure javascript. No hidden HTML or jQuery here for those of you who prefer to remove the overhead.

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