Se você precisar da resposta curta e técnica, vá direto para a última seção da resposta.
Se você quiser conhecer melhor, leia tudo, e espero que você goste ...
Eu lutei contra esse problema também hoje, e o que descobri hoje é o seguinte:
as respostas acima são verdadeiras, como:
1.1, está lhe dizendo que o cabeçalho que você está tentando adicionar já existe e você deve modificar seu valor usando a propriedade apropriada (o indexador, por exemplo), em vez de tentar adicioná-lo novamente.
1.2 Sempre que você alterar os cabeçalhos de um HttpWebRequest
, precisará usar as propriedades apropriadas no próprio objeto, se existirem.
Obrigado e Jvenema pelas principais diretrizes ...
Mas, o que eu descobri, e essa foi a peça que faltava no quebra - cabeça é que:
2.1 A WebHeaderCollection
classe geralmente é acessada através de WebRequest
.Headers ou WebResponse
.Headers. Alguns cabeçalhos comuns são considerados restritos e são expostos diretamente pela API (como Tipo de conteúdo) ou protegidos pelo sistema e não podem ser alterados.
Os cabeçalhos restritos são:
Accept
Connection
Content-Length
Content-Type
Date
Expect
Host
If-Modified-Since
Range
Referer
Transfer-Encoding
User-Agent
Proxy-Connection
Portanto, da próxima vez que você enfrentar essa exceção e não souber como solucionar isso, lembre-se de que existem alguns cabeçalhos restritos e a solução é modificar seus valores usando a propriedade apropriada explicitamente na classe WebRequest
/ HttpWebRequest
.
Editar: (útil, de comentários, comentário do usuário Kaido )
A solução é verificar se o cabeçalho já existe ou está restrito ( WebHeaderCollection.IsRestricted(key)
) antes de chamar add
Headers.Add()
já existe; portanto, devemos modificá-la.Corri para esse problema com um cliente Web personalizado. Eu acho que as pessoas podem estar ficando confusas por causa de várias maneiras de fazer isso. Ao usar,
WebRequest.Create()
você pode converter emHttpWebRequest
e usar a propriedade para adicionar ou modificar um cabeçalho. Ao usar um,WebHeaderCollection
você pode usar o.Add("referer","my_url")
.Ex 1
Ex 2
fonte
Todas as respostas anteriores descrevem o problema sem fornecer uma solução. Aqui está um método de extensão que resolve o problema, permitindo que você defina qualquer cabeçalho através do nome da string.
Uso
Classe de extensão
Cenários
Eu escrevi um wrapper para
HttpWebRequest
e não queria expor todos os 13 cabeçalhos restritos como propriedades no meu wrapper. Em vez disso, eu queria usar um simplesDictionary<string, string>
.Outro exemplo é um proxy HTTP, no qual você precisa pegar os cabeçalhos de uma solicitação e encaminhá-los ao destinatário.
Existem muitos outros cenários em que simplesmente não é prático ou possível usar propriedades. Forçar o usuário a definir o cabeçalho por meio de uma propriedade é um design muito inflexível e é por isso que a reflexão é necessária. O lado positivo é que a reflexão é abstraída, ainda é rápida (0,001 segundo nos meus testes) e, como um método de extensão, parece natural.
Notas
Os nomes de cabeçalho não diferenciam maiúsculas de minúsculas de acordo com o RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
fonte
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); } } }
Eu tive a mesma exceção quando meu código tentou definir o valor do cabeçalho "Accept" como este:
A solução foi alterá-lo para isso:
fonte
Sempre que você alterar os cabeçalhos de um
HttpWebRequest
, precisará usar as propriedades apropriadas no próprio objeto, se existirem. Se você tem uma planícieWebRequest
, certifique-se de convertê-la para umaHttpWebRequest
primeira. Então,Referrer
no seu caso, pode ser acessado via((HttpWebRequest)request).Referrer
, para que você não precise modificar o cabeçalho diretamente - basta definir a propriedade com o valor certo.ContentLength
,ContentType
,UserAgent
, Etc, tudo precisa ser definida desta forma.IMHO, isso é uma falha da parte do MS ... definir os cabeçalhos via
Headers.Add()
deve chamar automaticamente a propriedade apropriada nos bastidores, se é isso que eles querem fazer.fonte
WebRequest sendo abstrato (e como qualquer classe herdada deve substituir a propriedade Headers) .. qual WebRequest concreto você está usando? Em outras palavras, como você consegue alinhar esse objeto WebRequest?
ehr .. mnour resposta me fez perceber que a mensagem de erro que você estava recebendo está realmente correta: está dizendo que o cabeçalho que você está tentando adicionar já existe e você deve modificar seu valor usando a propriedade apropriada (o indexador, por exemplo ), em vez de tentar adicioná-lo novamente. Provavelmente é tudo o que você estava procurando.
Outras classes herdadas do WebRequest podem ter propriedades ainda melhores envolvendo determinados cabeçalhos; Veja este post, por exemplo.
fonte
As respostas acima são boas, mas a essência do problema é que alguns cabeçalhos são definidos de uma maneira e outros são definidos de outras maneiras. Veja acima as listas de 'cabeçalho restrito'. Para isso, basta defini-los como uma propriedade. Para outros, você realmente adiciona o cabeçalho. Veja aqui.
fonte
Basicamente, não. Como é um cabeçalho http, é razoável converter
HttpWebRequest
e definir o.Referer
(como você indica na pergunta):fonte
Nota: esta solução funcionará com WebClientSocket, HttpWebRequest ou qualquer outra classe que use WebHeaderCollection para trabalhar com cabeçalhos.
Se você olhar o código fonte do WebHeaderCollection.cs, verá que o Hinfo é usado para manter informações de todos os cabeçalhos conhecidos:
Observando a classe HeaderInfoTable, você pode observar que todos os dados são armazenados na tabela de hash
Além disso, no contratador estático do HeaderInfoTable, é possível ver todos os cabeçalhos conhecidos sendo adicionados à matriz HeaderInfo e copiados para a hashtable.
A análise final da classe HeaderInfo mostra os nomes dos campos.
Portanto, com todo o exposto, aqui está um código que usa reflexão para localizar Hashtable estático na classe HeaderInfoTable e altera todos os HeaderInfo restritos a solicitações dentro da tabela de hash para ser irrestrito
fonte
Estou usando apenas:
fonte
Você pode simplesmente converter o WebRequest em um HttpWebRequest mostrado abaixo:
e, em vez de tentar manipular a lista de cabeçalhos, aplique-a diretamente na propriedade de solicitação request.Referer:
Essas propriedades estão disponíveis no objeto de solicitação.
fonte