简体   繁体   English

如何将 JSON 字符串转换为 URL 参数(GET 请求)?

[英]How can I convert a JSON string to URL parameters (GET request)?

I have the following JSON which has to be converted to URL parameters for a GET request.我有以下 JSON,必须将其转换为 GET 请求的 URL 参数。

An example is given here , however due to the complexity of this object, there can be multiple line_items_attributes each with the given values as shown, I'm having difficulties passing on the correct one. 这里给出了一个例子,但是由于这个对象的复杂性,可以有多个line_items_attributes每个都具有给定的值,如图所示,我很难传递正确的值。

I've also tried to just serialize the JSON object and pass on that value but that did not solve the issue either.我还尝试仅序列化 JSON 对象并传递该值,但这也没有解决问题。

{
    "purchase_invoice":
    {
        "date":"14/04/2015",
        "due_date":"14/04/2015",
        "contact_id":500,
        "contact_name":"TestContact",
        "reference":"TestReference",
        "line_items_attributes":[
            {
                "unit_price":10.00,
                "quantity":1,
                "description":"TestLineItemAttDesc",
                "tax_code_id":1,
                "ledger_account_id":501,
                "tax_rate_percentage":19.0,
                "tax_amount":1.60

            }]
    }
}

I've been searching for a while now but without much luck.我一直在寻找一段时间,但没有太多运气。 Any insights are appreciated and most welcome!任何见解表示赞赏和欢迎!

This is calling an API which does not support the incoming data in JSON format, so doing this server-side or changing the web service to support data in JSON format is not possible.这是调用的 API 不支持 JSON 格式的传入数据,因此在服务器端执行此操作或更改 Web 服务以支持 JSON 格式的数据是不可能的。

x-www-form-urlencoded content is, essentially, a flat sequence of key/value tuples, and as explained in this answer to How do I use FormUrlEncodedContent for complex data types? x-www-form-urlencoded内容本质上是键/值元组的平面序列,正如在如何将 FormUrlEncodedContent 用于复杂数据类型的答案中所述 by Tomalak , there is no canonical way to transform a hierarchical, nested key/value structure into a flat one.通过Tomalak ,没有将分层的嵌套键/值结构转换为扁平结构的规范方法。

Nevertheless, from the accepted answer to this question, this example from the Stripe API, and the question mentioned above, it seems that it is common to flatten parameters inside complex nested objects by surrounding their keys in brackets and appending them to the topmost key like so:然而,从这个问题的公认答案这个来自 Stripe API 的例子,以及上面提到的问题,似乎通过将它们的键括在括号中并将它们附加到最上面的键,将复杂嵌套对象内的参数展平是很常见的,例如所以:

{
    { "purchase_invoice[date]", "14/04/2015" } 
    { "purchase_invoice[due_date]", "14/04/2015" } 
    { "purchase_invoice[contact_id]", "500" } 
    { "purchase_invoice[contact_name]", "TestContact" } 
    { "purchase_invoice[reference]", "TestReference" } 
    { "purchase_invoice[line_items_attributes][0][unit_price]", "10" } 
    { "purchase_invoice[line_items_attributes][0][quantity]", "1" } 
    { "purchase_invoice[line_items_attributes][0][description]", "TestLineItemAttDesc" } 
    { "purchase_invoice[line_items_attributes][0][tax_code_id]", "1" } 
    { "purchase_invoice[line_items_attributes][0][ledger_account_id]", "501" } 
    { "purchase_invoice[line_items_attributes][0][tax_rate_percentage]", "19" } 
    { "purchase_invoice[line_items_attributes][0][tax_amount]", "1.6" } 
}

If this is what you want, you can generate such key/value pairs with using the following extension methods:如果这是您想要的,您可以使用以下扩展方法通过生成此类键/值对:

public static partial class JsonExtensions
{
    public static string ToUrlEncodedQueryString(this JContainer container)
    {
        return container.ToQueryStringKeyValuePairs().ToUrlEncodedQueryString();
    }

    public static IEnumerable<KeyValuePair<string, string>> ToQueryStringKeyValuePairs(this JContainer container)
    {
        return container.Descendants()
            .OfType<JValue>()
            .Select(v => new KeyValuePair<string, string>(v.ToQueryStringParameterName(), (string)v));
    }

    public static string ToUrlEncodedQueryString(this IEnumerable<KeyValuePair<string, string>> pairs)
    {
        return string.Join("&", pairs.Select(p => HttpUtility.UrlEncode(p.Key) + "=" + HttpUtility.UrlEncode(p.Value)));
        //The following works but it seems heavy to construct and await a task just to built a string:
        //return new System.Net.Http.FormUrlEncodedContent(pairs).ReadAsStringAsync().Result;
        //The following works and eliminates allocation of one intermediate string per pair, but requires more code:
        //return pairs.Aggregate(new StringBuilder(), (sb, p) => (sb.Length > 0 ? sb.Append("&") : sb).Append(HttpUtility.UrlEncode(p.Key)).Append("=").Append(HttpUtility.UrlEncode(p.Value))).ToString();
        //Answers from https://stackoverflow.com/questions/3865975/namevaluecollection-to-url-query that use HttpUtility.ParseQueryString() are wrong because that class doesn't correctly escape the keys names.
    }

    public static string ToQueryStringParameterName(this JToken token)
    {
        // Loosely modeled on JToken.Path
        // https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JToken.cs#L184
        // By https://github.com/JamesNK
        if (token == null || token.Parent == null)
            return string.Empty;
        var positions = new List<string>();
        for (JToken previous = null, current = token; current != null; previous = current, current = current.Parent)
        {
            switch (current)
            {
                case JProperty property:
                    positions.Add(property.Name);
                    break;
                case JArray array:
                case JConstructor constructor:
                    if (previous != null)
                        positions.Add(((IList<JToken>)current).IndexOf(previous).ToString(CultureInfo.InvariantCulture)); // Don't localize the indices!
                    break;
            }
        }
        var sb = new StringBuilder();
        for (var i = positions.Count - 1; i >= 0; i--)
        {
            var name = positions[i];
            // TODO: decide what should happen if the name contains the characters `[` or `]`.
            if (sb.Length == 0)
                sb.Append(name);
            else
                sb.Append('[').Append(name).Append(']');
        }

        return sb.ToString();
    }
}

Then if you have a JSON string, you can parse it into a LINQ-to-JSON JObject and generate the query string like so:然后,如果您有一个 JSON 字符串,则可以将其解析为LINQ-to-JSON JObject并生成查询字符串,如下所示:

var obj = JObject.Parse(jsonString);
var queryString = obj.ToUrlEncodedQueryString();

Alternatively, if you have some hierarchical data model POCO, you can generate your JObject from the model using JObject.FromObject() :或者,如果您有一些分层数据模型 POCO,您可以使用JObject.FromObject()从模型生成JObject

var obj = JObject.FromObject(myModel);
var queryString = obj.ToUrlEncodedQueryString();

Demo fiddle here .演示小提琴在这里

So the final URL would be easy to compute using any URL Encoding mechanism .因此,使用任何URL 编码机制都可以轻松计算最终 URL。 In C#, we could do the following:在 C# 中,我们可以执行以下操作:

string json = "...";
string baseUrl = "http://bla.com/somepage?myJson="
string urlWithJson = baseUrl + System.Net.WebUtility.UrlEncode(json)

Is there any way you can POST the data or otherwise send a request body instead?有什么方法可以发布数据或以其他方式发送请求正文吗? It would seem slightly easier/cleaner.这似乎更容易/更清洁。

Sounds like you need something which is x-www-form-urlencoded .听起来你需要一些x-www-form-urlencoded

From your example, it would look like this:从您的示例中,它看起来像这样:

purchase_invoice%5Bdate%5D=14%2F04%2F2015&purchase_invoice%5Bdue_date%5D=14%2F04%2F2015&purchase_invoice%5Bcontact_id%5D=500&purchase_invoice%5Bcontact_name%5D=TestContact&purchase_invoice%5Breference%5D=TestReference&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Bunit_price%5D=10&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Bquantity%5D=1&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Bdescription%5D=TestLineItemAttDesc&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Btax_code_id%5D=1&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Bledger_account_id%5D=501&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Btax_rate_percentage%5D=19&purchase_invoice%5Bline_items_attributes%5D%5B0%5D%5Btax_amount%5D=1.6

The best reference for this encoding that I'm aware of is the undocumented jQuery.param method on the jQuery JavaScript library.我所知道的这种编码的最佳参考是 jQuery JavaScript 库中未记录的jQuery.param方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM