2009-10-19 21 views
11

Wystąpił problem z HttpWebRequest, że jeśli identyfikator URI ma więcej niż 2048 znaków, żądanie kończy się niepowodzeniem i zwraca błąd 404, mimo że serwer jest w stanie obsłużyć żądanie z długim identyfikatorem URI. Wiem o tym, ponieważ ten sam identyfikator URI, który powoduje błąd, jeśli został przesłany za pośrednictwem HttpWebRequest, działa poprawnie po wklejeniu bezpośrednio do paska adresu przeglądarki.HttpWebRequest obejście długi URI?

Moje bieżące obejście polega na umożliwieniu użytkownikom ustawienia flagi zgodności, aby powiedzieć, że można bezpiecznie wysłać parametry jako żądanie POST, w przypadku gdy identyfikator URI byłby zbyt długi, ale nie jest idealny, ponieważ protokół I ' m using to RESTful, a GET powinno być używane do zapytań. Poza tym nie ma gwarancji, że inni implementatorzy protokołu zaakceptują zapytania POSTed:

Czy istnieje inna klasa w .Net, która ma równoważną funkcjonalność do HttpWebRequest, która nie cierpi z powodu ograniczenia długości URI, którego mógłbym użyć?
Jestem świadomy WebClient, ale tak naprawdę nie chcę tego używać, ponieważ potrzebuję być w stanie w pełni kontrolować nagłówki HTTP, które WebClient ogranicza możliwość wykonania.

Edit

Ponieważ Shoban poprosił o nim:

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 

Która jest następująca kodowane na kwerendy:

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

}

+0

Chcę zobaczyć URL, który ma więcej niż 2048 znaków ;-) – Shoban

+0

@Shoban dodał przykład dla ciebie – RobV

Odpowiedz

6

się Protokół, którego używam, to RESTful, a GET powinien być używany do zapytań.

Nie ma powodu, że POST nie może być również używany do zapytań; w przypadku bardzo długich danych żądania, ponieważ bardzo długie identyfikatory URI nie są obsługiwane globalnie i nigdy nie były. Jest to jeden obszar, w którym HTTP nie spełnia ideału REST.

Powodem, dla którego POST na ogół nie jest używany na poziomie zwykłego HTML, jest zatrzymanie zapytania przeglądarki o ponowne załadowanie i promowanie np. zakładki. Ale dla HttpWebRequest nie masz żadnej z tych obaw, więc kontynuuj i POST to. Aplikacje internetowe powinny używać parametru lub części ścieżki URI, aby odróżnić żądania zapisu od zapytań, a nie tylko od metody żądania. (Oczywiście żądanie zapisu z metody GET powinno być nadal odrzucane.)

+0

Tak, zajrzałem do dokumentacji protokołu i mówi on, że implementatorzy MOGĄ wspierać zapytania POSTed, więc powinny wspierać em, ale nie ma żadnych gwarancji – RobV

+0

+1 POST to sposób na długie adresy URL. – db42

+0

Z metodologii i filozoficznego punktu widzenia to nonsens, ale DZIAŁA! Dzięki Ci. –

3

Nie sądzę, że HttpWebRequest jest w rzeczywistości niezgodny z adresami URL GET o rozmiarze, o którym mówisz. Mówię to na podstawie dwóch rzeczy:

  1. W mojej pracy używam HttpWebRequest do wysyłania żądań HTTP GET dłuższy niż 2048 znaków bez kłopotów. Nie jestem pewien, jakie są moje najdłuższe, ale mówimy o 10 000 postaciach. (Jest to przede wszystkim między aplikacją WWW a instancją Solr działającą pod Tomcat.)

  2. .NET ma pewne ograniczenia dotyczące długości adresów URL GET, ale te, o których wiem, są znacznie wyższe niż 2048 znaków. Na przykład, dzisiaj dowiedziałem się od mojego profilera, że ​​WebRequest.Create (adres URL łańcucha) wywołuje Uri class constructor i udokumentowane jest zgłoszenie wyjątku UriFormatException, jeśli "długość uriString przekracza 65534 znaków."

nie jestem pewien, gdzie może być problem, jeśli nie HttpWebRequest sama jest. Czy wiesz w jakich warunkach Twój serwis internetowy zwróci HTTP 404 (czyli«nie znaleziono»)? (Zakładam 404 pochodzi z twojej usługi sieciowej, a nie jest sfałszowany w głębi .NET.) Chciałbym również dwukrotnie sprawdzić, czy adres, który wklejasz do przeglądarki, jest w rzeczywistości tym samym, który jest wysyłany przez .NET , jak zasugerował feroze, powinieneś użyć do tego celu narzędzia do podsłuchiwania sieci.Jeśli te dwa adresy są takie same, to może następnie porównaj sposób, w jaki nagłówki HTTP różnią się między przypadkiem .NET a przypadkiem przeglądarki. (Nawiasem mówiąc, osobiście znajduję Fiddler bit handier niż wireshark do zadań debugowania HTTP wzdłuż tych linii.)

Zobacz także to nieco pokrewne pytanie: How does HttpWebRequest differ (functional) from pasteing a URL into an address bar?

0

Twój ciąg zapytania jest nieprawidłowy zgodnie z RFC3986. Znaki "{" i "}" są niedozwolone w identyfikatorze URI.

+0

Huh, podany identyfikator URI jest generowany przez metodę .NET Uri.EscapeDataString(), nie jest pewien, który RCP URI, który jest zgodny z – RobV

2

Oto fragment, który konstruuje HttpWebRequest instancji z większych i większych wartości URL dopóki pobiera wyjątek:

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!"); 

Na moim komputerze (w LINQPad systemem .NET 4.5), ten fragment Wyjścia:

Error occurred at url length: 65520 
System.UriFormatException: Invalid URI: The Uri string is too long.