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

StackOverflow https://stackoverflow.com/questions/239725

  •  04-07-2019
  •  | 
  •  

Вопрос

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

Этот заголовок необходимо изменить с помощью соответствующего свойства.

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

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

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

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

Это было полезно?

Решение

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

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


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

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

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

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

Спасибо FOR и Jvenema за ведущие рекомендации...

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

    2.1 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 сорт.


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

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

Другие советы

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

Пример 1

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

Пример 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-прокси, где вам нужно взять заголовки запроса и переслать их получателю.

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

Примечания

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

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

ИМХО, это недостаток со стороны MS ... установка заголовков через <=> должна автоматически вызывать соответствующее свойство за кулисами, если это то, что они хотят делать.

У меня было то же исключение, когда мой код пытался установить " 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 быть привязанным?

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

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

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

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

    request.Accept = "application/json";

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

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

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

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

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

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

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

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

request.Referer = "yourReferer";

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top