Не удается установить некоторые заголовки HTTP при использовании System. Net. WebRequest


когда я пытаюсь добавить пару ключ/значение заголовка HTTP на WebRequest объект, я получаю следующее исключение:

этот заголовок должен быть изменен с помощью соответствующего свойства

Я пробовал добавлять новые значения в Headers коллекция с помощью метода Add (), но я все равно получаю то же исключение.

webRequest.Headers.Add(HttpRequestHeader.Referer, "http://stackoverflow.com");

Я могу обойти это, приведя объект WebRequest к HttpWebRequest и установив такие свойства, как httpWebReq.Referer ="http://stackoverflow.com", но это работает только для нескольких заголовков, которые доступны через свойства.

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

10 116

10 ответов:

если вам нужен короткий и технический ответ, перейдите прямо к последнему разделу ответа.

если вы хотите знать лучше, прочитайте все это, и я надеюсь, что вам понравится...


я тоже сегодня столкнулся с этой проблемой, и сегодня я обнаружил, что:

  1. приведенные выше ответы верны, как:

    1.1 он говорит вам, что заголовок, который вы пытаетесь добавить, уже существует, и вы должны изменить его значение с помощью соответствующее свойство (индексатор, например), вместо того, чтобы пытаться добавить его снова.

    1.2 в любое время вы меняете заголовки HttpWebRequest, вам нужно использовать соответствующие свойства на самом объекте, если они существуют.

Спасибо за и Jvenema для ведущих руководящих принципов...

  1. но, что я узнал, и это была недостающая часть головоломки это:

    2.1 The WebHeaderCollection класс, как правило, доступны через WebRequest.Заголовки или WebResponse.Заголовки. некоторые общие заголовки считаются ограниченными и либо предоставляются непосредственно API (например, Content-Type), либо защищены системой и не могут быть изменены.

только заголовки являются:

  • Accept
  • Connection
  • Content-Length
  • Content-Type
  • Date
  • Expect
  • Host
  • If-Modified-Since
  • Range
  • Referer
  • Transfer-Encoding
  • User-Agent
  • Proxy-Connection

Итак, в следующий раз, когда вы столкнетесь с этим исключением и не знаете, как решить эту проблему, помните что есть некоторые ограниченные заголовки, и решение состоит в том, чтобы изменить их значения, используя соответствующее свойство явно из WebRequest/HttpWebRequest класса.


Edit: (полезно, из комментариев, комментарий пользователя Кайдо)

решение состоит в том, чтобы проверить, существует ли заголовок уже или ограничен (WebHeaderCollection.IsRestricted(key)) перед вызовом добавить

я столкнулся с этой проблемой с помощью пользовательского веб-клиента. Я думаю, что люди могут запутаться из-за нескольких способов сделать это. При использовании WebRequest.Create() вы можете привести к HttpWebRequest и используйте свойство для добавления или изменения заголовка. При использовании WebHeaderCollection можно использовать .Add("referer","my_url").

Ex 1

WebClient client = new WebClient();
client.Headers.Add("referer", "http://stackoverflow.com");
client.Headers.Add("user-agent", "Mozilla/5.0");

Ex 2

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Referer = "http://stackoverflow.com";
request.UserAgent = "Mozilla/5.0";
response = (HttpWebResponse)request.GetResponse();

все предыдущие ответы описывают проблему без предоставления решения. Вот метод расширения, который решает проблему, позволяя вам установить любой заголовок через его строковое имя.

использование

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.SetRawHeader("content-type", "application/json");

Расширение Класс

public static class HttpWebRequestExtensions
{
    static string[] RestrictedHeaders = new string[] {
            "Accept",
            "Connection",
            "Content-Length",
            "Content-Type",
            "Date",
            "Expect",
            "Host",
            "If-Modified-Since",
            "Keep-Alive",
            "Proxy-Connection",
            "Range",
            "Referer",
            "Transfer-Encoding",
            "User-Agent"
    };

    static Dictionary<string, PropertyInfo> HeaderProperties = new Dictionary<string, PropertyInfo>(StringComparer.OrdinalIgnoreCase);

    static HttpWebRequestExtensions()
    {
        Type type = typeof(HttpWebRequest);
        foreach (string header in RestrictedHeaders)
        {
            string propertyName = header.Replace("-", "");
            PropertyInfo headerProperty = type.GetProperty(propertyName);
            HeaderProperties[header] = headerProperty;
        }
    }

    public static void SetRawHeader(this HttpWebRequest request, string name, string value)
    {
        if (HeaderProperties.ContainsKey(name))
        {
            PropertyInfo property = HeaderProperties[name];
            if (property.PropertyType == typeof(DateTime))
                property.SetValue(request, DateTime.Parse(value), null);
            else if (property.PropertyType == typeof(bool))
                property.SetValue(request, Boolean.Parse(value), null);
            else if (property.PropertyType == typeof(long))
                property.SetValue(request, Int64.Parse(value), null);
            else
                property.SetValue(request, value, null);
        }
        else
        {
            request.Headers[name] = value;
        }
    }
}

сценарии

Я написал обертку для HttpWebRequest и не хотел выставлять все 13 ограниченных заголовков в качестве свойств в моей оболочке. Вместо этого я хотел использовать простой Dictionary<string, string>.

другой пример-HTTP прокси, где вам нужно взять заголовки в запросе и переслать их получателю.

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

Примечания

имена заголовков нечувствительны к регистру в RFC,http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2

в любое время вы меняете заголовки HttpWebRequest, вам нужно использовать соответствующие свойства на самом объекте, если они существуют. Если у вас есть равнина WebRequest, обязательно приведите его к HttpWebRequest первый. Тогда Referrer в вашем случае можно получить доступ через ((HttpWebRequest)request).Referrer, поэтому вам не нужно изменять заголовок напрямую-просто установите свойство в нужное значение. ContentLength,ContentType,UserAgent и т. д., Все должны быть установлены таким образом.

ИМХО, это недостаток на МС части...установка заголовки через Headers.Add() должен автоматически вызывать соответствующее имущество за кулисами, если это то, что они хотят сделать.

у меня было такое же исключение, когда мой код пытался установить значение заголовка "Accept" следующим образом:

WebRequest request = WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Headers.Add("Accept", "application/json");

решение состояло в том, чтобы изменить его на это:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Accept = "application/json";

WebRequest будучи абстрактным (и так как любой наследующий класс должен переопределить свойство Headers).. какой конкретный WebRequest вы используете ? Другими словами, как вы получаете этот объект WebRequest для разработки ?

ehr.. ответ mnour заставил меня понять, что сообщение об ошибке, которое вы получаете, на самом деле находится на месте: оно говорит вам, что заголовок, который вы пытаетесь добавить, уже существует, и вы должны затем изменить его значение, используя соответствующее свойство (индексатор, например), вместо того, чтобы добавить его снова. Это, наверное, все, что вы искали.

другие классы, наследующие от WebRequest, могут иметь еще лучшие свойства, обертывающие определенные заголовки; см. этот пост например.

в принципе, нет. Это заголовок http, поэтому разумно привести к HttpWebRequest и выберите .Referer (Как вы указываете в вопросе):

HttpWebRequest req = ...
req.Referer = "your url";

приведенные выше ответы все в порядке, но суть проблемы заключается в том, что некоторые заголовки устанавливаются в одну сторону, а другие-в другую. См. выше для списков "ограниченный заголовок". Для них вы просто устанавливаете их как свойство. Для других, вы на самом деле добавить заголовок. Видеть здесь.

    request.ContentType = "application/x-www-form-urlencoded";

    request.Accept = "application/json";

    request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);

Я использую только:

request.ContentType = "application/json; charset=utf-8"

Вы можете просто привести WebRequest к HttpWebRequest, показанному ниже:

var request = (HttpWebRequest)WebRequest.Create(myUri);

и затем вместо того, чтобы пытаться манипулировать списком заголовков, примените его непосредственно в запросе свойства запроса.Референт:

request.Referer = "yourReferer";

эти свойства доступны в объекте запроса.