【问题标题】:Is there a standard syntax for encoding structure objects as HTTP GET request parameters?是否有将结构对象编码为 HTTP GET 请求参数的标准语法?
【发布时间】:2011-02-11 06:15:45
【问题描述】:

想象一下,我们需要将一些结构化对象传递给 Web 应用程序——例如,语言环境、布局设置和一些查询的定义。这可以通过类似于以下片段的 JSON 或 XML 轻松完成:

<Locale>en</Locale>  
<Layout>  
  <Block id="header">hide</Block>  
  <Block id="footer">hide</Block>  
  <Block id="navigation">minimize</Block>  
</Layout>  
<Query>  
  <What>water</What>  
  <When>  
    <Start>2010-01-01</Start>  
  </When>  
</Query>

但是,使用 HTTP 传递此类结构意味着(粗略地说)HTTP POST。

现在假设我们仅限于 HTTP GET。在 HTTP GET 请求参数中编码结构化数据是否有某种标准解决方案?

我可以很容易地想象出这样的事情:

Locale=en&
Layout.Block.header=hide&
Layout.Block.footer=hide&
Layout.Block.navigation=minimize&
Query.What=water&
Query.When.Start=2010-01-01

但我正在寻找的是“标准”语法,如果有的话。

ps。我肯定知道 URL 长度的问题。请假设在这种情况下这不是问题。

pps。我也很乐意提供指向键值对 URL API(如 Paypal NVP)的链接,您认为值得一看。

pps。我们当然可以预见回调 URL,但我们也需要 HTTP GET 键值对。问题集中在后者。

【问题讨论】:

    标签: xml json http data-structures


    【解决方案1】:

    这取决于您要如何解码。如果您有一个专门知道如何沿&amp;=(即PHP)拆分参数和值的系统,那么您的解决方案就可以工作,但是如果取消了该限制,那么它可以变得更加简洁:

    Locale{en}Layout{Block(id:header){hide}Block(id:footer){hide}Block(id:navigation){minimize}}Query{What{water}When{Start{2010-01-01}}}
    

    简而言之,没有标准(据我所知),所以根据您的需要进行创意。您甚至可以使用 JSON,根据需要省略或编码空格。

    【讨论】:

    • 你引用的语法是标准的吗? JSON 确实是一种选择,但它的优雅将被 URL 编码完全破坏。
    • 不。我只是根据我认为简洁和美观的方式来实现它。
    【解决方案2】:

    这个想法只有在你可以控制服务器和客户端并且两者都可以通过网络相互访问时才有效。

    客户端:

    调用服务器的客户端需要在 HTTP-REQUEST 的 HTTP-HEADER 中传递一个回调 URL。该 URL 还将具有唯一 ID,并且示例 REQUEST 可能如下所示。

    //HTTP Request Header
    
    GET / HTTP/1.1[CRLF]
    Host: www.your-server.com/server-end.aspx[CRLF]
    Connection: close[CRLF]
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)[CRLF]
    Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7[CRLF]
    Cache-Control: no[CRLF]
    Accept-Language: de,en;q=0.7,en-us;q=0.3[CRLF]
    Referer: some referrer[CRLF]
    Input-callback-Url: www.your-client.com/inputprovider.aspx?requestid=xxxxxxx[CRLF]
    [CRLF]
    

    服务器端:

    在服务器端,服务器将从客户端读取 Http-Request 的标头,并读取在“Input-callback-Url”中接收到的 Url。然后服务器将在 www.your-client.com/inputprovider.aspx?requestid=xxxxxxx 上发起 Http-Request GET。当服务器调用此 URL 时,将以 JASON 或 XML 形式呈现输出。

    <Locale>en</Locale>          
    <Layout>          
      <Block id="header">hide</Block>          
      <Block id="footer">hide</Block>          
      <Block id="navigation">minimize</Block>          
    </Layout>          
    <Query>          
      <What>water</What>          
      <When>          
        <Start>2010-01-01</Start>          
      </When>          
    </Query>
    

    服务器可以从“Input-callback-Url”接收此响应并继续提供原始客户端请求。

    【讨论】:

    • 我们当然预见到回调 URL(处理较长 URL 的方法之一)。然而,这需要客户端付出巨大的努力,因此我们不希望它成为 only 方法。我们确实需要键值对编码来允许简单的链接,例如可以插入到 CMS/Wiki/论坛中。无论如何,我要为一个明智的想法 +1。
    【解决方案3】:

    我明白你的问题很好。我喜欢并且多年来一直在使用 XML 和 XML 模式。半年以来,我使用 JavaScript 和 jQuery 以及 RESTfull WFC 服务、带有 JSON 编码数据的 ASP.NET MVC 技术进行传输。所以前段时间我不得不问我同样的问题。这是我的回答和简短的解释。

    您定义的 XML 结构可以代表我们 Web 服务的一个输入参数。如果您更喜欢将 XML 结构划分为不同的输入参数(如 Locale、Layout 和 Query),那么我在这里写的所有内容都可以轻松修改为这种参数编码的情况。

    在我看来,最原生的方式是我们使用开箱即用的工具实现的方式。因此,让我们拥有一个带有类似MyMethod 的方法的Web 服务和一个带有MyData 类型的输入参数param1(类似public int MyMethod (MyData param1))。 MyData 类代表我们所有来自 XML 结构的数据。那么对应的 HTTP GET 请求应该是这样的

    http://server/Service/MyMethod?param1=JsonEncodedData

    在哪里JsonEncodedData

    %7B%22locale%22%3A%22en%22%2C%22layout%22%3A%5B%7B%22id%22%3A%22header%22%2C%22value%22%3A%22hide%22% 7D%2C%7B%22id%22%3A%22footer%22%2C%22value%22%3A%22hide%22%7D%2C%7B%22id%22%3A%22navigation%22%2C%22value%

    或没有HTML编码的相同:

    {"locale":"en","layout":[{"id":"header","value":"hide"},{"id":"footer","value":"hide "},{"id":"navigation","value":"minimize"}],"query":{"what":"water","when":{"Start":{"Year":2010 ,"月":1,"日":1}}}

    此数据是 JSON 编码的 JavaScript 对象

    var myInput = {
      locale: "en",
      layout:[
        {id: "header", value: "hide"},
        {id: "footer", value: "hide"},
        {id: "navigation", value: "minimize"}
      ],
      query:{
        what: "water",
        when: {
          Start:{Year:2010,Month:1,Day:1}
        }
      }
    };
    

    备注:因为Date JavaScript 类可以用一些不同的方式序列化,所以我在这里稍微改变了开始日期的表示。在“微软世界”中,我们可以使用Sys.Serialization.JavaScriptSerializer.serialize 序列化DateTime .NET 类型,该类型将编码 2010-01-01,如“/Date(1262300400000)/”。

    我们可以用C#写一个简单的Web服务方法Service1.asmx之类的

    [WebMethod]
    [ScriptMethod (UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public int MyMethod (MyData param1) {
        return param1.query.when.Start.Year;
    }
    

    在哪里

    public enum BlockType {
        hide,
        minimize
    }
    public class Block {
        public string id { get; set; }
        //public BlockType value { get; set; }
        public string value { get; set; }
    }
    public class MyDate {
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
    }
    public class When {
        public MyDate Start { get; set; }
    }
    public class Query {
        public string what { get; set; }
        public When when { get; set; }
    }
    public class MyData {
        public string locale;
        public List<Block> layout;
        public Query query;
    }
    

    相应的客户端代码如下所示

    var myInput = {
      locale: "en",
      layout:[
        {id: "header", value: "hide"},
        {id: "footer", value: "hide"},
        {id: "navigation", value: "minimize"}
      ],
      query:{
        what: "water",
        when: {
          Start:{Year:2010,Month:1,Day:1}
        }
      }
    };
    
    $.ajax({
        type: "GET",
        url: "/Service1.asmx/Method2",
        data: {param1: JSON.stringify(myInput)},
        contentType: "application/json; charset=utf-8",
        success: function(data, textStatus, XMLHttpRequest) {
            alert(XMLHttpRequest.responseText);
        },
        error: function(res, status) {
            if (status ==="error") {
                // errorMessage can be an object with 3 string properties:
                //      ExceptionType, Message and StackTrace
                var errorMessage = $.parseJSON(res.responseText);
                alert(errorMessage.Message);
            }
        }
    });
    

    对于我在示例 json2.js 中使用的 JSON 编码(参见 https://github.com/douglascrockford/JSON-js/blob/master/json2.jshttp://www.json.org/js.html)。可以使用 JSON jQuery(来自 http://code.google.com/p/jquery-json/),然后将 JSON.stringify 替换为 $.toJSON

    MyData 类型数据的初始化可能如下所示

    new MyData {
            locale = "en",
            layout = new List<Block> {
                new Block() { id="header", value=BlockType.hide.ToString()},
                new Block() { id="footer", value=BlockType.hide.ToString()},
                new Block() { id="navigation", value=BlockType.minimize.ToString()}
            },
            query = new Query {
                what = "water",
                //when = new When() {Start = new DateTime(2010,1,1)}
                when = new When () {
                    Start = new MyDate () {
                        Year = 2010,
                        Month = 1,
                        Day = 1
                    }
                }
            }
        };
    }
    

    如果您将 WCF 与 webHttpBinding(RESTfull 端点)一起使用,而不是基于 asmx 的 Web 服务,您可以获得更灵活的解决方案。

    如果将 JSON 与 HTTP GET 一起使用,则应考虑到 JSON 劫持问题的存在(请参阅http://weblogs.asp.net/scottgu/archive/2007/04/04/json-hijacking-and-how-asp-net-ajax-1-0-mitigates-these-attacks.aspxhttp://haacked.com/archive/2009/06/25/json-hijacking.aspx)。这个问题可以通过不同的方式解决(或显着减少),它不会阻止我在 HTTP 请求中使用 JSON,它可以完美缓存。

    有关同一主题的更多信息,您可以查看我对关闭问题的回答: How do I build a JSON object to send to an AJAX WebService? Can I return JSON from an .asmx Web Service if the ContentType is not JSON? JQuery ajax call to httpget webmethod (c#) not working

    【讨论】:

    • 感谢您的详细帖子。 JSON 编码的问题是很难手动处理。控件符号是 URL 编码的,括号必须匹配等等。这种语法肯定适合 JS 程序员,但它对“最终”用户不友好,在这种情况下,我们的目标群体是我们。我们终于得出结论,没有“标准”编码,所以我们开发了自己的语法。当我们准备好解析器时,我会描述它。
    • 对不起,但在我看来,没有人(作为一个人)会手动构建并调用具有超过 10 个参数的 URL。因此,您应该从双方(客户端和服务器)编写一个程序,对一些表示数据的结构进行编码和解码。我尝试使用最简单的 de- 和 JSON 编码为 JavaScript 和 .NET Web 服务建议一种本机方式。您的问题中编码的缺点是客户端和服务器都必须保存不是结构,而是许多单独的变量。什么更好?
    • 需求是存在的,而不是想象的。这是我们的客户所需要的。实际上,有很多这样的 API - 有 PayPal NVP,有 Google Charts,还有 OGC 之类的 WMS 等等。 “最终用户”是像专业系统管理员或应用程序维护者这样的人,他们需要一个简单的 URL API 来将我们的应用程序集成到他/她的环境中。是的,我们可以提供额外的工具,例如“这是你必须用来构建 URL 的东西”,但这不能是排他性的,因为它会降低接受度(这会影响销售数字)。
    • “什么更好?” - 好吧,我同意 KVP-> 对象结构有点挑战,并且 JSON 或 XML 在这里更容易处理。但这只是我们欣然接受的技术挑战。
    • 现在您的要求将更加清晰。在cms.paypal.com/us/cgi-bin/… 的另一边,有不同的参考资料如何进行 URL 编码。如果您为客户提供如何使用 JSON 编码参数的良好示例,就足够了。还有一个“所罗门的解决方案”:您可以为您的客户建议两种方式,然后查看统计数据,看看哪种方式能更好地找到客户。
    【解决方案4】:

    嗯,在 URI 中编码数据的标准方法是 application/x-www-form-urlencoded大多数 应用程序处理分层数据的方式是在关键部分使用方括号。例如:

    Locale=en&
    Layout[Block][header]=hide&
    Layout[Block][footer]=hide&
    Layout[Block][navigation]=minimize&
    Query[What]=water&
    Query[When][Start]=2010-01-01
    

    这在某种程度上是特定于应用程序的,但它非常接近成为事实上的标准

    【讨论】:

    • 这个“接近成为事实上的标准”是否记录在任何地方?我不记得以前见过这种语法。我将不胜感激参考。谢谢!
    • 不,这是轶事。 PHP 和 Ruby on Rails 都使用该语法,这是我的陈述的基础。
    • @frank 我实际上并不确定这样的文件是否存在。我可以写一个,但这会破坏目的。
    • @troelskn:这有助于 RoR dizzy.co.uk/ruby_on_rails/cheatsheets/form-helpers#example - html 在第 3.3 节中
    【解决方案5】:

    据我所知,没有使用 GET 传递结构化数据的标准。有一些约定(上面的 PHP/RoR 示例可能是最流行的),但没有任何成熟度、文档、参考实现等被视为标准。

    没有出现一个简单的标准也就不足为奇了。有一些悬而未决的问题,其答案取决于具体情况。 URL 应该是透明的(作为可见的查询参数)还是不透明的(例如 base64 编码)。可以使用压缩吗?可以/应该/必须使用/支持其他表示,例如JSON、二进制 XML 甚至 Google 的 protocol buffers)。 URL溢出如何处理? 10 个不同的人可能都会根据他们的情况给出不同的答案。一个标准可以尝试解决所有这些问题,但这远非简单。

    即使有标准,遵循它是否有意义?

    遵循一个标准是可取的,甚至是令人欣慰的,知道您的工作是建立在受人尊敬的现场专家和工程师经过道路测试的工作之上,并且知道我们被邀请参加聚会并与其他遵循的系统一起玩相同的标准。但是当需求多种多样时,就像这里一样,标准通常只会给你一个折中的解决方案,一种妥协的媒介。当你只有2K 可以玩时,妥协可能是你名单上的最后一个!

    自己动手,一定会得到你想要的。我会去表示为二进制 XML 或协议缓冲区,gzipped 和 base64 编码,但你的 Millage 可能会有所不同。

    无论如何,祝你好运!

    【讨论】:

    • 这也是我得出的结论。我们已经在路上了。
    猜你喜欢
    • 2012-10-21
    • 2016-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多