簡體   English   中英

如何使用同步頁面 POST 從 HTML 表單發送復雜的 JSON 對象?

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

我的服務器正在使用 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,同時仍然具有正常的“頁面提交”行為)?

雖然 Mythz 建議發布 JSV 值是可行的,但有時在 JavaScript 中構建和維護復雜的 JSV 會很麻煩。 例如,您可能必須處理轉義用戶輸入的數據,並且語法問題可能難以跟蹤

這個解決方案看起來很復雜,但實際上並不復雜,並且高度可重用,只需要您可以發送編碼的 JSON,這在 jQuery 中非常簡單。

完整的演示源代碼在這里

過程 - 工作原理:

  1. 您的 jQuery 使用提交時的表單數據創建 DTO
  2. DTO 編碼為 JSON,只需使用JSON.stringify(data)
  3. JSON 以隱藏形式作為Data字段的值發送
  4. 服務器 DTO 屬性過濾器將Data字段的 JSON 值反序列化為您的 DTO
  5. 您的服務會看到 DTO 正常填充。

過濾器屬性:

我的解決方案在表單發布中將編碼為 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 字符串並提交
$("#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>

ServiceStack 可以使用 JSV 格式 POST 復雜類型,例如:

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

然后您可以按原樣 POST 瀏覽器將使用x-www-form-urlencoded Content-Type 執行的操作,甚至可以使用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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM