Существует ли стандартный синтаксис для кодирования объектов структуры в качестве параметров запроса HTTP GET? - PullRequest
2 голосов
/ 23 апреля 2010

Представьте, что нам нужно передать в веб-приложение ряд структурированных объектов - например, локаль, настройки макета и определение какого-либо запроса. Это можно легко сделать с помощью 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

Но я ищу "стандартный" синтаксис, если таковой имеется.

пс. Я точно знаю о проблеме с длиной URL. Пожалуйста, предположите, что в этом случае это не проблема.

имп. Я также был бы признателен за ссылки на URL-интерфейсы пары ключ-значение (например, Paypal NVP ), на которые, по вашему мнению, стоит обратить внимание.

ЧГП. Мы, конечно, ожидаем URL обратных вызовов, но нам также нужны пары ключ-значение HTTP GET. Вопрос касается последнего.

Ответы [ 5 ]

3 голосов
/ 02 мая 2010

Ну, стандартный способ кодирования данных в URI - application/x-www-form-urlencoded. Способ, которым большинство приложений обрабатывают иерархические данные, заключается в квадратных скобках в ключевой части. Eg.:

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

Это в некоторой степени зависит от конкретного приложения, но фактически является стандартом де-факто

2 голосов
/ 23 апреля 2010

Это зависит от того, как вы хотите его декодировать. Ваше решение работает, если у вас есть система, которая знает, как разделять параметры и значения по & и = (т.е. 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, пропуская или кодируя пробелы по мере необходимости.

1 голос
/ 05 мая 2010

Насколько мне известно, не существует стандартов для передачи структурированных данных с использованием GET. Существует несколько соглашений (пример PHP / RoR, приведенный выше, возможно, наиболее распространенный), но ничто не достигло какого-либо уровня зрелости, документации, ссылочной реализации и т. Д. ..., чтобы считаться стандартом.

И не удивительно, что простой стандарт не появился. Есть открытые вопросы, ответы на которые зависят от специфики ситуации. Должен ли URL быть прозрачным (как видимые параметры запроса) или непрозрачным (например, закодированным в base64). Можно ли использовать сжатие? Могут ли / должны / должны быть использованы / поддерживаться другие представления, например, JSON, двоичный XML или даже буфер протокола от Google ). Как обрабатывается переполнение URL? 10 разных людей могут дать разные ответы о том, что нужно, исходя из их ситуации. Стандарт может попытаться решить все эти проблемы, но тогда это будет далеко не просто.

Даже если бы существовал какой-то стандарт, имеет ли смысл его соблюдать?

Желательно, даже утешительно, следовать стандарту, зная, что ваша работа строится на проверенной на дороге работе уважаемых полевых экспертов и инженеров, и зная, что мы приглашены на вечеринку и поиграем с другими системами, которые следуют тот же стандарт. Но когда требуемые материалы разнообразны, как они есть здесь, стандарт, как правило, дает вам только решение среднего уровня, средство компромисса. А когда у вас есть только 2K , компримирование, вероятно, будет последним в вашем списке!

Сверните свое, и вы обязательно получите именно то, что хотите. Я хотел бы представлять в виде двоичного XML или буфера протокола, в кодировке gzipped и base64, но вы можете варьировать.

В любом случае, удачи!

1 голос
/ 02 мая 2010

Я понимаю, что вы задали очень хороший вопрос. Я люблю и использую XML и XML-схему уже много лет. С полугода я использую JavaScript и jQuery вместе со службами RESTfull WFC, технологиями ASP.NET MVC с данными в кодировке JSON для передачи. Поэтому мне пришлось задать мне тот же вопрос некоторое время назад. Вот мой ответ с кратким объяснением.

XML-структура, которую вы определяете, может представлять один входной параметр нашей веб-службы. Если вы предпочитаете разделять структуру XML на разные входные параметры (например, Locale, Layout и Query), все, что я здесь напишу, может быть легко модифицировано для этого случая кодирования параметров.

На мой взгляд, наиболее естественным является способ, которым мы реализуем с использованием готовых инструментов . Итак, позвольте нам иметь наш веб-сервис с методом, подобным MyMethod, и входным параметром param 1 с типом MyData (что-то вроде 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-кодировки:

{ "локаль": "ан", "макет": [{ "ID": "заголовок", "значение": "шкурку"}, { "ID": "колонтитул", "значение": "скрыть "}, {" ID ":" навигация», "значение": "минимизировать"}], "запрос": { "что": "вода", "когда": { "Start": { "Год": 2010 , "месяц": 1, "День": 1}}}

Эти данные являются объектом JavaScript в кодировке JSON

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

ЗАМЕЧАНИЕ : Поскольку класс JavaScript Date может быть сериализован несколькими различными способами, я немного изменил представление даты начала здесь. В «мире Microsoft» мы можем использовать Sys.Serialization.JavaScriptSerializer.serialize для сериализации DateTime .NET типа, который будет кодировать 2010-01-01 как "/Date(1262300400000)/".

Мы можем написать на C # простой веб-метод Web Service 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);
        }
    }
});

Для кодирования JSON я использую в примере json2.js (см. https://github.com/douglascrockford/JSON-js/blob/master/json2.js и http://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, вы можете получить более гибкое решение.

Если вы используете 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.aspx, http://haacked.com/archive/2009/06/25/json-hijacking.aspx). Эта проблема может быть решена (или значительно уменьшена) различными способами и это не мешает мне использовать JSON в HTTP-запросах, которые могут быть идеально кэшированы.

Для получения дополнительной информации по той же теме вы можете просмотреть мой ответ на закрытые вопросы: Как создать объект JSON для отправки в AJAX WebService? Можно ли вернуть JSON из веб-службы .asmx, если ContentType не является JSON? JQuery AJAX-вызов веб-метода httpget (c #) не работает

1 голос
/ 28 апреля 2010

Эта идея будет работать, только если у вас есть контроль как на сервере, так и на клиенте, и оба они взаимно доступны по сети.

Конец клиента:

Клиент, вызывающий сервер, должен будет передать URL-адрес обратного вызова в HTTP-HEADER HTTP-REQUEST.URL также будет иметь уникальный идентификатор, и пример запроса может выглядеть следующим образом.

//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-запроса от клиента и считывать URL-адрес, полученный в «Input-callback-Url».Затем сервер инициирует запрос Http-запроса по адресу www.your-client.com/inputprovider.aspx?requestid=xxxxxxx.Этот 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" и продолжить обработку исходного клиентского запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...