2009-12-11 18 views
8

Ho il seguente problema. Io contatto un indirizzo che conosco utilizza un reindirizzamento 301.C# HttpWebResponse Codifica dell'intestazione

utilizzando HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl); e loHttp.AllowAutoRedirect = false; in modo da non essere reindirizzato.

Ora ottengo l'intestazione della risposta per identificare il nuovo URL.

utilizzando loWebResponse.GetResponseHeader("Location");

Il problema è che dal momento che questo URL contiene i caratteri greci la stringa restituita è tutto mescolate (a causa di codifica).

Il quadro completo codewise:

HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl); 
loHttp.ContentType = "application/x-www-form-urlencoded"; 
loHttp.Method = "GET"; 

Timeout = 10000; 

loHttp.AllowAutoRedirect = false; 
HttpWebResponse loWebResponse = (HttpWebResponse)loHttp.GetResponse(); 

string url= loWebResponse.Headers["Location"]; 
+1

Per impostazione predefinita 'HttpWebRequest' seguirà i reindirizzamenti, quindi se un server invia il codice di stato' 301/302' verrà inviata una nuova richiesta per recuperare la risorsa usando l'intestazione 'Location'. Quindi, una volta che questa risorsa finale è stata recuperata, non ci sarà più un'intestazione 'Location' nella risposta, quindi mi chiedo come sia che' loWebResponse.GetResponseHeader ("Posizione") 'restituisce qualcosa di diverso da una stringa vuota. A parte questo, hai verificato con 'FireBug' che il sito esegue una codifica corretta sull'intestazione' Location'? –

+1

Non ho chiarito che 'loHttp.AllowAutoRedirect = false;' è impostato in modo da poter ispezionare l'url di reindirizzamento –

risposta

6

Se si attiva il comportamento predefinito (loHttp.AllowAutoRedirect = true) e il codice non funziona (non viene reindirizzato alla nuova risorsa) significa che il server non codifica l'intestazione Location correttamente. Il reindirizzamento funziona nel browser?

Ad esempio se l'URL di reindirizzamento è http://site/Μία_Σελίδα, l'intestazione Ubicazione deve apparire come http://site/%CE%95%CE%BD%CE%B9%CE%B1%CE%AF%CE%BF_%CE%94%CE%B5%CE%.


UPDATE:

Dopo aver esaminato ulteriormente la questione comincio a sospettare che ci sia qualcosa di strano con HttpWebRequest. Quando la richiesta viene inviata al server invia la seguente risposta:

HTTP/1.1 301 Moved Permanently 
Date: Fri, 11 Dec 2009 17:01:04 GMT 
Server: Microsoft-IIS/6.0 
X-Powered-By: ASP.NET 
Location: http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/ 
Content-Length: 112 
Content-Type: text/html; Charset=UTF-8 
Cache-control: private 
Connection: close 
Set-Cookie: BIGipServerpool_webserver_gr=1007732746.36895.0000; path=/ 


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 

Come possiamo vedere l'intestazione Location contiene caratteri greci che non sono URL codificato. Non sono del tutto sicuro se questo è valido secondo lo HTTP specification. Quello che possiamo dire con certezza è che un browser web lo interpreta correttamente.

Ecco che arriva la parte interessante. Sembra che HttpWebRequest non utilizzi la codifica UTF-8 per analizzare le intestazioni di risposta perché quando si analizza l'intestazione Location fornisce: http://www.site.com/buy/κινηÏή-ÏÏαθεÏή-ÏηλεÏÏνία/c/cn69569/, che ovviamente è errato e quando tenta di reindirizzare a questa posizione il server risponde con un nuovo reindirizzamento e così via fino a quando non viene raggiunto il numero massimo di reindirizzamenti e viene generata un'eccezione.

Non ho trovato alcun modo per specificare la codifica utilizzata da HttpWebRequest durante l'analisi delle intestazioni di risposta. Se usiamo TcpCLient manualmente funziona perfettamente bene:

using (var client = new TcpClient()) 
{ 
    client.Connect("www.site.com", 80); 

    using (var stream = client.GetStream()) 
    { 
     var writer = new StreamWriter(stream); 
     writer.WriteLine("GET /default/defaultcatg.asp?catg=69569 HTTP/1.1"); 
     writer.WriteLine("Host: www.site.com"); 
     writer.WriteLine("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090805 Shiretoko/3.5.2"); 
     writer.WriteLine("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); 
     writer.WriteLine("Accept-Language: en-us,en;q=0.5"); 
     writer.WriteLine("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"); 
     writer.WriteLine("Connection: close"); 
     writer.WriteLine(string.Empty); 
     writer.WriteLine(string.Empty); 
     writer.WriteLine(string.Empty); 
     writer.Flush(); 

     var reader = new StreamReader(stream); 
     var response = reader.ReadToEnd(); 
     // When looking at the response it correctly reads 
     // Location: http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/ 
    } 
} 

quindi sono davvero perplesso da questo comportamento. C'è un modo per specificare la codifica corretta usata da HttpWebRequest? Forse dovrebbe essere impostata un'intestazione di richiesta?

Come soluzione alternativa, provare a modificare la pagina asp che esegue il reindirizzamento e urlencode l'intestazione Location. Ad esempio, quando in un'applicazione ASP.NET si esegue uno Response.Redirect(location), la posizione verrà automaticamente codificata in html e tutti i caratteri non standard verranno convertiti nelle entità corrispondenti.

Per esempio se si fa: Response.Redirect("http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/"); in un'applicazione ASP.NET l'intestazione Location verrà impostato:

http://www.site.com/buy/%ce%ba%ce%b9%ce%bd%ce%b7%cf%84%ce%ae-%cf%83%cf%84%ce%b1%ce%b8%ce%b5%cf%81%ce%ae-%cf%84%ce%b7%ce%bb%ce%b5%cf%86%cf%89%ce%bd%ce%af%ce%b1/c/cn69569 

Sembra che questo non è il caso di ASP classico.

+0

se la lascio su true, allora ottengo un'eccezione (sia un timeout che un'eccezione di reindirizzamenti massimi). Nel browser funziona bene in termini di raggiungere la pagina giusta. Quindi la mia ipotesi è che sto facendo qualcosa di sbagliato nella lettura degli header di Location. –

+0

C'è qualche possibilità che tu possa postare l'URL reale in modo che io possa dargli un'occhiata? O forse non è pubblicamente accessibile? –

+2

In .Net, l'analisi delle intestazioni viene gestita in una codifica "ASCII pura" incapsulata all'interno della classe WebHeaderCollection. Questo è conforme alla RFC 2616. Chiunque stia distribuendo quell'intestazione di Location è SBAGLIATO, ma la maggior parte dei browser "semplicemente gestiscono", assumendo che il set di caratteri sia UTF-8 (cosa c'è nel flusso di ottetti effettivo). – IDisposable

1

non mi aspetto la stringa restituita da malformato ... come stai determinare che è deforme? La stringa dovrebbe essere in un formato unicode come utf-8 che sarebbe in grado di rappresentare facilmente la stringa greca.

Potrebbe essere che non hai i caratteri greci per rappresentare la stringa?

+0

in modo errato, cioè non in una codifica leggibile. questo è ciò che il getResponseHeader ritorna "http://www.site.com/buy/κινηÏή-ÏÏαθÎμÏή-ÏηλÎμÏÏνία/c/cn69569/" –

+0

hmmm in Visual Studio sembra un po 'diverso: S ma comunque come vedi la parte centrale è rovinata –

1

Come spiega Darin Dimitrov, credo che la codifica dell'intestazione sia causata da un errore nella classe HttpWebResponse. Abbiamo avuto lo stesso problema in cui volevamo aggiungere un cookie all'intestazione (Set-Cookie) e questo cookie conterrebbe caratteri non Ascii. Nel nostro caso specifico sarebbero le lettere norvegesi "Æ", "Ø" e "Å" (in lettere maiuscole e minuscole). Non siamo riusciti a capire come far funzionare HeaderEncoding, ma abbiamo trovato un modo per aggirare il problema usando la codifica Base64 del cookie. Si noti che ciò funzionerà solo se si ha il controllo sul lato client e server (oppure si può convincere i responsabili del codice lato server per aggiungere la codifica Base64 per voi ...)

sul lato server:

var cookieData = "This text contains Norwegian letters; ÆØÅæøå"; 
var cookieDataAsUtf8Bytes = System.Text.Encoding.UTF8.GetBytes(cookieData); 
var cookieDataAsUtf8Base64Encoded = Convert.ToBase64String(cookieDataAsUtf8Bytes); 
var cookie = new HttpCookie("MyCookie", cookieDataAsUtf8Base64Encoded); 
response.Cookies.Add(cookie); 

sul lato client:

var cookieDataAsUtf8Bytes = Convert.FromBase64String(cookieDataAsUtf8Base64Encoded); 
var cookieData = System.Text.Encoding.UTF8.GetString(cookieDataAsUtf8Bytes); 

noti che cookieDataAsUtf8Base64Encoded sul lato client è la parte dei dati del cookie (cioè 'MyCookie = [i dati]', dove 'MyCookie =' viene rimosso).