Обходной путь длинного URI HttpWebRequest?

Я столкнулся с проблемой HttpWebRequest: если длина URI превышает 2048 символов, запрос не выполняется и возвращает ошибку 404, даже если сервер вполне способен обслуживать запрос с таким длинным URI. Я знаю это, поскольку тот же URI, который вызывает ошибку при отправке через HttpWebRequest, отлично работает при вставке непосредственно в адресную строку браузера.

Мой текущий обходной путь - позволить пользователям установить флаг совместимости, чтобы сказать, что безопасно отправлять параметры в виде запроса POST вместо этого в случае, когда URI будет слишком длинным, но это не идеально, поскольку я использую протокол RESTful. и GET следует использовать для запросов. Кроме того, нет гарантии, что другие разработчики протокола будут принимать запросы POSTed.

Есть ли в .Net другой класс, который имеет эквивалентную функциональность HttpWebRequest, который не страдает от ограничения длины URI, которое я мог бы использовать?
Я знаю о WebClient, но я действительно не хочу его использовать, поскольку мне нужно чтобы иметь возможность полностью контролировать HTTP-заголовки, которые WebClient ограничивает.

Изменить

Потому что об этом просил Шобан:

http://localhost/BBCDemo/sparql/?query=PREFIX+rdf%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%3E%0D%0APREFIX+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0D%0APREFIX+xsd%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%23%3E%0D%0APREFIX+skos%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23%3E%0D%0APREFIX+dc%3A+%3Chttp%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%3E%0D%0APREFIX+po%3A+%3Chttp%3A%2F%2Fpurl.org%2Fontology%2Fpo%2F%3E%0D%0APREFIX+timeline%3A+%3Chttp%3A%2F%2Fpurl.org%2FNET%2Fc4dm%2Ftimeline.owl%23%3E%0D%0ASELECT+*+WHERE+{%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+dc%3Atitle+%3Ftitle+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Ashort_synopsis+%3Fsynopsis-short+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Amedium_synopsis+%3Fsynopsis-med+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Along_synopsis+%3Fsynopsis-long+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Amasterbrand+%3Fchannel+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Agenre+%3Fgenre+.%0D%0A++++%3Fchannel+dc%3Atitle+%3Fchanneltitle+.%0D%0A++++OPTIONAL+{%0D%0A++++++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Abrand+%3Fbrand+.%0D%0A++++++++%3Fbrand+dc%3Atitle+%3Fbrandtitle+.%0D%0A++++}%0D%0A++++OPTIONAL+{%0D%0A++++++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Aversion+%3Fver+.%0D%0A++++++++%3Fver+po%3Atime+%3Finterval+.%0D%0A++++++++%3Finterval+timeline%3Astart+%3Fstart+.%0D%0A++++++++%3Finterval+timeline%3Aend+%3Fend+.%0D%0A++++}%0D%0A}&default-graph-uri=&timeout=30000

В строке запроса закодировано следующее:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX po: <http://purl.org/ontology/po/>
PREFIX timeline: <http://purl.org/NET/c4dm/timeline.owl#>
SELECT * WHERE {
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> dc:title ?title .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:short_synopsis ?synopsis-short .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:medium_synopsis ?synopsis-med .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:long_synopsis ?synopsis-long .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:masterbrand ?channel .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:genre ?genre .
  ?channel dc:title ?channeltitle .
  OPTIONAL {
    <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:brand ?brand .
    ?brand dc:title ?brandtitle .
  }
  OPTIONAL {
    <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:version ?ver .
    ?ver po:time ?interval .
    ?interval timeline:start ?start .
    ?interval timeline:end ?end .
  }

}


person RobV    schedule 19.10.2009    source источник
comment
Я хочу увидеть URL-адрес, который превышает 2048 символов ;-)   -  person Shoban    schedule 19.10.2009
comment
@Shoban добавил вам пример   -  person RobV    schedule 19.10.2009


Ответы (4)


я использую протокол RESTful, а для запросов следует использовать GET.

Нет причин, по которым POST нельзя использовать и для запросов; для действительно длинных данных вы должны это делать, так как очень длинные URI не поддерживаются глобально и никогда не поддерживались. Это одна из областей, где HTTP не соответствует идеалу REST.

Причина, по которой POST обычно не используется на уровне простого HTML, заключается в том, чтобы остановить запрос браузера на перезагрузку и продвигать, например. закладки. Но для HttpWebRequest у вас нет ни одной из этих проблем, поэтому вперед и отправьте его POST. Веб-приложения должны использовать параметр или часть пути URI, чтобы отличать запросы записи от запросов, а не только метод запроса. (Конечно, запрос на запись от метода GET все равно должен быть отклонен.)

person bobince    schedule 19.10.2009
comment
Да, я просмотрел документацию по протоколу, и там говорится, что разработчики МОГУТ поддерживать POSTed запросы, поэтому они должны поддерживать их, но нет никаких гарантий. - person RobV; 19.10.2009
comment
С методологической и философской точки зрения это ерунда, но это РАБОТАЕТ! Спасибо. - person Pavel Shkleinik; 11.08.2015

Я не думаю, что HttpWebRequest на самом деле несовместим с URL-адресами GET того размера, о котором вы говорите. Я говорю это, основываясь на двух вещах:

  1. В своей работе я использую HttpWebRequest для беспроблемной отправки HTTP-запросов GET длиной более 2048 символов. Я не уверен, какие у меня самые длинные, но мы говорим о 10 000+ символов. (Это в первую очередь между веб-приложением и экземпляром Solr, работающим под Tomcat.)

  2. .NET имеет некоторые ограничения на длину URL-адресов GET, но те, о которых я знаю, намного превышают 2048 символов. Например, сегодня я узнал от своего профилировщика, что WebRequest.Create (строковый URL) вызывает конструктор класса Uri, и это задокументировано для выдачи исключения UriFormatException, если «длина uriString превышает 65534 символа».

Я не уверен, где может быть ваша проблема, если это не сам HttpWebRequest. Знаете ли вы, при каких условиях ваш веб-сервис будет возвращать HTTP 404 (т. Е. «Не найден»)? (Я предполагаю, что 404 исходит от вашего веб-сервиса, а не подделывается в недрах .NET.) Я также хотел бы дважды проверить, что адрес, который вы вставляете в браузер, на самом деле тот же, что и отправлено .NET; как предложил Фероз, для этого вам следует использовать инструмент сетевого сниффинга. Если два адреса совпадают, то, возможно, в следующий раз сравните, как заголовки HTTP различаются между случаем .NET и случаем браузера. (Между прочим, я лично считаю, что Fiddler немного удобнее, чем wirehark, для задач отладки HTTP в этих направлениях.)

См. Также этот несколько связанный вопрос: Чем HttpWebRequest отличается (функционально) от вставки URL-адреса в адресную строку?

person Chris    schedule 27.02.2010

Вот фрагмент, который создает HttpWebRequest экземпляры с все большими и большими значениями URL-адресов до тех пор, пока не будет создано исключение:

using System.Net;

...

StringBuilder url = new StringBuilder("http://example.com?p=");
try
{
    for (int i = 1; i < Int32.MaxValue; i++)
    {
        url.Append("0");
        HttpWebRequest request = HttpWebRequest.CreateHttp(url.ToString());
    }
}
catch (Exception ex)
{
    Console.Out.WriteLine("Error occurred at url length: " + url.Length);
    Console.Out.WriteLine(ex.GetType().ToString() + ": " + ex.Message);
    return;
}
Console.Out.WriteLine("Completed without error!");

На моей машине (в LINQPad с .Net 4.5) этот фрагмент выводит:

Error occurred at url length: 65520
System.UriFormatException: Invalid URI: The Uri string is too long.
person Jon Schneider    schedule 18.09.2015

Ваша строка запроса неверна в соответствии с RFC3986. В URI нельзя использовать символы '{' и '}'.

person aycanirican    schedule 17.10.2010
comment
Да, указанный URI генерируется методом Uri.EscapeDataString() .Net, но не уверен, какой URI RFC соответствует, хотя - person RobV; 18.10.2010