Если вам нужен краткий и технический ответ, перейдите сразу к последнему разделу ответа.
Если вы хотите узнать лучше, прочтите все это, и я надеюсь, вам понравится ...
Сегодня я тоже решил эту проблему, и сегодня я обнаружил следующее:
приведенные выше ответы верны, так как:
1.1 он сообщает вам, что заголовок, который вы пытаетесь добавить, уже существует, и вы должны затем изменить его значение, используя соответствующее свойство (например, индексатор), вместо того, чтобы пытаться добавить его снова.
1.2 Каждый раз, когда вы меняете заголовки HttpWebRequest
, вам необходимо использовать соответствующие свойства самого объекта, если они существуют.
Спасибо FOR и Jvenema за руководящие принципы ...
Но вот что я выяснил, и это был недостающий элемент в головоломке :
2.1 WebHeaderCollection
Доступ к классу обычно осуществляется через WebRequest
.Headers или WebResponse
.Headers. Некоторые общие заголовки считаются ограниченными и либо предоставляются непосредственно 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
Headers.Add()
уже существует, поэтому мы должны изменить его.Я столкнулся с этой проблемой с помощью специального веб-клиента. Я думаю, что люди могут запутаться из-за множества способов сделать это. При использовании
WebRequest.Create()
вы можете привестиHttpWebRequest
и использовать свойство для добавления или изменения заголовка. При использованииWebHeaderCollection
вы можете использовать.Add("referer","my_url")
.Пример 1
Пример 2
источник
Все предыдущие ответы описывают проблему, не предлагая решения. Вот метод расширения, который решает проблему, позволяя вам установить любой заголовок через его строковое имя.
использование
Класс расширения
Сценарии
Я написал оболочку для
HttpWebRequest
и не хотел показывать все 13 ограниченных заголовков как свойства в моей оболочке. Вместо этого я хотел использовать простойDictionary<string, string>
.Другой пример - HTTP-прокси, в котором вам нужно взять заголовки в запросе и переслать их получателю.
Есть много других сценариев, в которых использование свойств просто непрактично или невозможно. Принуждение пользователя к установке заголовка через свойство - очень негибкий дизайн, поэтому необходимо отражение. Положительным моментом является то, что отражение абстрагируется, оно по-прежнему быстрое (0,001 секунды в моих тестах) и как метод расширения кажется естественным.
Ноты
Имена заголовков нечувствительны к регистру согласно RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2.
источник
static Dictionary<string, PropertyInfo> HeaderProperties = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase); static WebRequestExtensions() { // Get property info for restricted headers. Type type = typeof(HttpWebRequest); foreach (string header in Enum.GetNames(typeof(HttpRequestHeader))) { var property = type.GetProperty(header.ToString()); if (property != null) { HeaderProperties.Add(property.Name, property); } } }
У меня было такое же исключение, когда мой код пытался установить значение заголовка «Принять» следующим образом:
Решением было изменить его на это:
источник
Каждый раз, когда вы меняете заголовки
HttpWebRequest
, вам необходимо использовать соответствующие свойства самого объекта, если они существуют. Если у вас есть равнинаWebRequest
, обязательно забросьте ееHttpWebRequest
первым. ЗатемReferrer
в вашем случае к нему можно получить доступ через((HttpWebRequest)request).Referrer
, поэтому вам не нужно напрямую изменять заголовок - просто установите для свойства правильное значение.ContentLength
,ContentType
,UserAgent
И т.д., все должны быть установлены таким образом.IMHO, это недостаток со стороны MS ... установка заголовков через
Headers.Add()
должна автоматически вызывать соответствующее свойство за кулисами, если это то, что они хотят сделать.источник
WebRequest является абстрактным (и поскольку любой наследующий класс должен переопределять свойство Headers) .. какой конкретный WebRequest вы используете? Другими словами, как заставить этот объект WebRequest соответствовать?
эх .. ваш ответ заставил меня понять, что сообщение об ошибке, которое вы получаете, на самом деле правильное: оно говорит вам, что заголовок, который вы пытаетесь добавить, уже существует, и вы должны затем изменить его значение, используя соответствующее свойство (например, индексатор ) вместо того, чтобы пытаться добавить его снова. Вероятно, это все, что вы искали.
Другие классы, унаследованные от WebRequest, могут иметь даже лучшие свойства, обертывающие определенные заголовки; См., Например, этот пост .
источник
Все вышеперечисленные ответы хороши, но суть проблемы в том, что одни заголовки задаются одним способом, а другие - другим. См. Выше списки «ограниченных заголовков». Для этого вы просто устанавливаете их как свойство. Для других вы фактически добавляете заголовок. Посмотреть здесь.
источник
В основном нет. Это заголовок http, поэтому разумно
HttpWebRequest
указать и установить.Referer
(как вы указываете в вопросе):источник
Примечание: это решение будет работать с WebClientSocket, а также с HttpWebRequest или любым другим классом, который использует WebHeaderCollection для работы с заголовками.
Если вы посмотрите исходный код WebHeaderCollection.cs, вы увидите, что Hinfo используется для хранения информации обо всех известных заголовках:
Глядя на класс HeaderInfoTable, можно заметить, что все данные хранятся в хэш-таблице.
Кроме того, в статическом конструкторе HeaderInfoTable вы можете видеть, что все известные заголовки добавляются в массив HeaderInfo, а затем копируются в хеш-таблицу.
Последний взгляд на класс HeaderInfo показывает имена полей.
Итак, со всем вышеперечисленным, вот код, который использует отражение для поиска статической Hashtable в классе HeaderInfoTable, а затем изменяет каждый ограниченный запросом HeaderInfo внутри хеш-таблицы, чтобы он был неограниченным.
источник
Я использую только:
источник
Вы можете просто передать WebRequest в HttpWebRequest, показанный ниже:
а затем вместо того, чтобы пытаться манипулировать списком заголовков, примените его непосредственно в запросе свойства запроса.
Эти свойства доступны в объекте запроса.
источник