如何使用FormUrlEncodedContent复杂的数据类型

本文关键字:数据类型 复杂 FormUrlEncodedContent 何使用 | 更新日期: 2023-09-27 18:17:10

我需要与只接受表单编码的有效负载的第三方端点进行交互。端点需要复杂的数据类型,这意味着类似于以下内容(但是是表单编码的,而不是JSON):

{
    "foo": "bar",
    "baz": {
        "zip": "zap"
    }
}

我的谷歌和文档的端点表明,这应该是这样的形式编码:

foo=bar&baz[zip]=zap

我正在使用HttpClient,我想使用FormUrlEncodedContent,但当我这样做时,它正在用转义字符替换我的[]

public class Tests
{
    [Fact]
    public void Test()
    {
        var content = new Dictionary<String, String>
        {
            { "foo", "bar" },
            { "baz[zip]", "zap" }
        };
        var formContent = new FormUrlEncodedContent(content);
        Assert.Equal("foo=bar&baz[zip]=zap", formContent.ReadAsStringAsync().Result);
    }
}

我最终得到的是:

foo=bar&baz%5Bzip%5D=zap

如何使用FormUrlEncodedContent复杂的数据类型

你的问题有两个问题。第一:

我的谷歌显示这应该是这样的形式编码:

foo=bar&baz[zip]=zap

。目前还没有将多维键值结构转换为一维键值结构的约定或标准。

如果你仔细想想,这样的转换会很快变得非常笨拙。对象语义比url编码语义更具表现力。顺便说一句,他们甚至不能就如何将普通数组编码为url达成一致,尽管这很容易实现。

既然没有标准,那就建立一个服务器和客户端都能接受的约定。最不让人头疼的约定是(*):

  • 将对象序列化为JSON。这给你一个字符串。
  • 将该字符串作为URL参数的值。
  • 接收端反向操作

在JS中你可以这样写:

encodeURIComponent(JSON.stringify({
    "foo": "bar",
    "baz": {
        "zip": "zap"
    }
}));

得到

"%7B%22foo%22%3A%22bar%22%2C%22baz%22%3A%7B%22zip%22%3A%22zap%22%7D%7D"

这可以作为一个URL参数安全地传输,并且可以以最小的努力进行处理。

对于。net,你可以从几个序列化选项中进行选择,其中两个是DataContractJsonSerializer和JavaScriptSerializer,在这里讨论。

我强烈建议不要为这个任务滚动您自己的序列化方案。


第二个

:

但是当我这样做时,它将用转义字符替换我的[]。

当然

。url编码的键-值对中的键遵循与值相同的规则。像{"a&b": "c&d"}这样的一对将被编码为a%26b=c%26d。实际上,您可以将其发送为%61%26%62=%63%26%64。换句话说,url解码值但是在接收端忘记url解码密钥名称是一个错误。忘记URL-编码键名也是如此。关于什么字符可以在URL中以什么形式使用的讨论在这里。


(*)直接将数据传输为Content-Type: application/json,这比将其压缩到查询字符串中更可取。