c# Кодировка заголовка HttpWebResponse

У меня следующая проблема. Я связываюсь с адресом, который, как я знаю, использует перенаправление 301.

используя HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl); и loHttp.AllowAutoRedirect = false;, чтобы меня не перенаправляли.

Теперь я получаю заголовок ответа, чтобы определить новый URL-адрес.

используя loWebResponse.GetResponseHeader("Location");

Проблема в том, что, поскольку этот URL-адрес содержит греческие символы, возвращаемая строка перемешана (из-за кодировки).

Полная картина по коду:

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"];

person Alexandros B    schedule 11.12.2009    source источник
comment
По умолчанию HttpWebRequest будет следовать перенаправлениям, поэтому, если сервер отправляет код состояния 301/302, будет выдан новый запрос на получение ресурса с использованием заголовка Location. Итак, как только этот последний ресурс будет получен, в ответе больше не будет заголовка Location, поэтому мне интересно, как получается, что loWebResponse.GetResponseHeader("Location") возвращает что-либо, кроме пустой строки. Помимо этого, вы проверили с помощью FireBug, что сайт правильно кодирует заголовок Location?   -  person Darin Dimitrov    schedule 11.12.2009
comment
Я не дал понять, что "loHttp.AllowAutoRedirect = false;" установлен, поэтому я могу проверить URL-адрес перенаправления   -  person Alexandros B    schedule 11.12.2009


Ответы (3)


Если вы разрешите поведение по умолчанию (loHttp.AllowAutoRedirect = true) и ваш код не работает (вы не будете перенаправлены на новый ресурс), это означает, что сервер неправильно кодирует заголовок Location. Редирект работает в браузере?

Например, если URL-адрес перенаправления http://site/Μία_Σελίδα, заголовок Location должен выглядеть как http://site/%CE%95%CE%BD%CE%B9%CE%B1%CE%AF%CE%BF_%CE%94%CE%B5%CE%.


ОБНОВИТЬ:

После дальнейшего изучения вопроса я начинаю подозревать, что с HttpWebRequest что-то странное. При отправке запроса сервер отправляет следующий ответ:

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">

Как мы видим, заголовок Location содержит греческие символы, которые не закодированы в URL. Я не совсем уверен, что это действительно в соответствии с HTTP-спецификацией< /а>. Что мы можем сказать наверняка, так это то, что веб-браузер правильно его интерпретирует.

А вот и самое интересное. Кажется, что HttpWebRequest не использует кодировку UTF-8 для разбора заголовков ответа, потому что при анализе заголовка Location выдает: http://www.site.com/buy/κινηÏή-ÏÏαθεÏή-ÏηλεÏÏνία/c/cn69569/, что, конечно, неверно, и когда он пытается перенаправить в это место, сервер отвечает новым перенаправлением и и так до тех пор, пока не будет достигнуто максимальное количество перенаправлений и не будет выдано исключение.

Я не смог найти способ указать кодировку, используемую HttpWebRequest при разборе заголовков ответа. Если мы используем TcpCLient вручную, все работает отлично. :

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

Так что я действительно озадачен этим поведением. Есть ли способ указать правильную кодировку, используемую HttpWebRequest? Может быть, какой-то заголовок запроса должен быть установлен?

В качестве обходного пути вы можете попробовать изменить страницу asp, которая выполняет перенаправление, и urlencode заголовок Location. Например, когда в приложении ASP.NET вы выполняете Response.Redirect(location), местоположение будет автоматически закодировано в формате html, а любые нестандартные символы будут преобразованы в соответствующие им объекты.

Например, если вы выполните: Response.Redirect("http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/"); в приложении ASP.NET, заголовок Location будет иметь значение:

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

Кажется, что это не так с классическим ASP.

person Darin Dimitrov    schedule 11.12.2009
comment
если я оставлю это значение true, то я получу исключение (либо тайм-аут, либо исключение максимального перенаправления). В браузере работает нормально в плане перехода на нужную страницу. Итак, я предполагаю, что я делаю что-то неправильно при чтении заголовков Location. - person Alexandros B; 11.12.2009
comment
Есть ли шанс, что вы могли бы опубликовать фактический URL-адрес, чтобы я мог на него взглянуть? Или, может быть, он не является общедоступным? - person Darin Dimitrov; 11.12.2009
comment
В .Net синтаксический анализ заголовков выполняется в чистой кодировке ASCII, инкапсулированной внутри класса WebHeaderCollection. Это соответствует RFC 2616. Тот, кто раздает этот заголовок Location, ДЕЛАЕТ ЭТО НЕПРАВИЛЬНО, но большинство браузеров просто обрабатывают его, предполагая, что кодировка - это UTF-8 (то, что находится в фактическом потоке октетов). - person IDisposable; 07.10.2011

Я бы не ожидал, что возвращаемая строка будет искажена... как вы определили, что она искажена? Строка должна быть в формате Unicode, таком как utf-8, который сможет легко представлять греческую строку.

Может быть, у вас просто нет греческих шрифтов для представления строки?

person John Weldon    schedule 11.12.2009
comment
под деформированным я имею в виду не в читаемой кодировке. это то, что возвращает getResponseHeader site.com/buy/ - person Alexandros B; 11.12.2009
comment
хм, в визуальной студии это выглядит немного иначе: S, но все же, как вы видите, средняя часть разрушена. - person Alexandros B; 11.12.2009

Как объясняет Дарин Димитров, я считаю, что кодировка заголовка вызвана ошибкой в ​​классе HttpWebResponse. У нас была та же проблема, когда мы хотели добавить файл cookie в заголовок (Set-Cookie), и этот файл cookie будет содержать символы, отличные от Ascii. В нашем конкретном случае это будут норвежские буквы «Æ», «Ø» и «Å» (в верхнем и нижнем регистре). Мы не могли понять, как заставить HeaderEncoding работать, но нашли обходной путь, используя кодировку Base64 файла cookie. Обратите внимание, что это будет работать только в том случае, если вы контролируете и клиентскую, и серверную часть (или вы можете убедить людей, отвечающих за код на стороне сервера, добавить для вас кодировку Base64... )

На стороне сервера:

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

На стороне клиента:

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

Обратите внимание, что cookieDataAsUtf8Base64Encoded на стороне клиента — это часть данных файла cookie (то есть «MyCookie=[data]», где «MyCookie=» удалена).

person Kjetil Klaussen    schedule 05.09.2011