Jeśli potrzebujesz krótkiej i technicznej odpowiedzi, przejdź od razu do ostatniej części odpowiedzi.
Jeśli chcesz wiedzieć lepiej, przeczytaj to wszystko i mam nadzieję, że Ci się spodoba ...
Dzisiaj również rozwiązałem ten problem i dzisiaj odkryłem, że:
powyższe odpowiedzi są prawdziwe, ponieważ:
1.1 mówi ci, że nagłówek, który próbujesz dodać, już istnieje i powinieneś zmodyfikować jego wartość przy użyciu odpowiedniej właściwości (na przykład indeksatora), zamiast próbować dodać go ponownie.
1.2 Za każdym razem, gdy zmieniasz nagłówki an HttpWebRequest
, musisz użyć odpowiednich właściwości samego obiektu, jeśli takie istnieją.
Dzięki za i Jvenema za wiodące wytyczne ...
Ale dowiedziałem się, a to był brakujący element układanki :
2.1 WebHeaderCollection
Klasa jest ogólnie dostępna poprzez WebRequest
.Headers lub WebResponse
.Headers. Niektóre typowe nagłówki są uważane za ograniczone i są albo ujawniane bezpośrednio przez API (takie jak Content-Type), albo chronione przez system i nie można ich zmienić.
Ograniczone nagłówki to:
Accept
Connection
Content-Length
Content-Type
Date
Expect
Host
If-Modified-Since
Range
Referer
Transfer-Encoding
User-Agent
Proxy-Connection
Więc następnym razem, gdy napotkasz ten wyjątek i nie wiesz, jak go rozwiązać, pamiętaj, że istnieją pewne ograniczone nagłówki, a rozwiązaniem jest zmodyfikowanie ich wartości za pomocą odpowiedniej właściwości jawnie z WebRequest
/ HttpWebRequest
class.
Edycja: (przydatne, z komentarzy, komentarz użytkownika Kaido )
Rozwiązaniem jest sprawdzenie, czy nagłówek już istnieje lub czy jest ograniczony ( WebHeaderCollection.IsRestricted(key)
) przed wywołaniem add
Headers.Add()
już istnieje, dlatego powinniśmy ją zmodyfikować.Napotkałem ten problem z niestandardowym klientem internetowym. Myślę, że ludzie mogą być zdezorientowani z powodu wielu sposobów, aby to zrobić. Podczas używania
WebRequest.Create()
możesz rzutować naHttpWebRequest
i użyć właściwości, aby dodać lub zmodyfikować nagłówek. Podczas korzystania z plikuWebHeaderCollection
możesz użyć.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();
źródło
Wszystkie poprzednie odpowiedzi opisują problem bez podania rozwiązania. Oto metoda rozszerzenia, która rozwiązuje problem, umożliwiając ustawienie dowolnego nagłówka za pomocą nazwy ciągu.
Stosowanie
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; request.SetRawHeader("content-type", "application/json");
Klasa rozszerzenia
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; } } }
Scenariusze
Napisałem opakowanie dla
HttpWebRequest
i nie chciałem ujawniać wszystkich 13 ograniczonych nagłówków jako właściwości w moim opakowaniu. Zamiast tego chciałem użyć prostego plikuDictionary<string, string>
.Innym przykładem jest serwer proxy HTTP, w którym musisz pobrać nagłówki w żądaniu i przesłać je do odbiorcy.
Istnieje wiele innych scenariuszy, w których użycie właściwości jest po prostu niepraktyczne lub niemożliwe. Zmuszanie użytkownika do ustawienia nagłówka za pomocą właściwości jest bardzo nieelastycznym projektem, dlatego potrzebne jest odbicie. Zaletą jest to, że odbicie jest wyabstrahowane, nadal jest szybkie (0,001 sekundy w moich testach), a jako metoda rozszerzenia wydaje się naturalne.
Uwagi
W nazwach nagłówków wielkość liter nie jest rozróżniana zgodnie z RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
źródło
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); } } }
Wystąpił ten sam wyjątek, gdy mój kod próbował ustawić wartość nagłówka „Accept” w następujący sposób:
WebRequest request = WebRequest.Create("http://someServer:6405/biprws/logon/long"); request.Headers.Add("Accept", "application/json");
Rozwiązaniem było zmienić to na to:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long"); request.Accept = "application/json";
źródło
Za każdym razem, gdy zmieniasz nagłówki an
HttpWebRequest
, musisz użyć odpowiednich właściwości samego obiektu, jeśli istnieją. Jeśli masz zwykłyWebRequest
, pamiętaj, aby rzucić go naHttpWebRequest
pierwszy. NastępnieReferrer
w twoim przypadku można uzyskać dostęp za pośrednictwem((HttpWebRequest)request).Referrer
, więc nie musisz bezpośrednio modyfikować nagłówka - po prostu ustaw właściwość na odpowiednią wartość.ContentLength
,ContentType
,UserAgent
, Itp, wszyscy muszą być ustawione w ten sposób.IMHO, to jest wada w części MS ... ustawienie nagłówków przez
Headers.Add()
powinno automatycznie wywoływać odpowiednią właściwość za kulisami, jeśli to jest to, co chcą zrobić.źródło
Żądanie WebRequest jest abstrakcyjne (i ponieważ każda klasa dziedzicząca musi przesłonić właściwość Headers) .. jakiego konkretnego żądania WebRequest używasz? Innymi słowy, jak sprawić, by obiekt WebRequest był używany?
ehr .. mnour odpowiedź uświadomiła mi, że otrzymany komunikat o błędzie jest rzeczywiście na miejscu: mówi ci, że nagłówek, który próbujesz dodać, już istnieje i powinieneś zmodyfikować jego wartość używając odpowiedniej właściwości (na przykład indeksator ), zamiast próbować dodać go ponownie. To prawdopodobnie wszystko, czego szukałeś.
Inne klasy dziedziczące po WebRequest mogą mieć jeszcze lepsze właściwości zawijające określone nagłówki; Zobacz na przykład ten post .
źródło
Wszystkie powyższe odpowiedzi są w porządku, ale istota problemu polega na tym, że niektóre nagłówki są ustawione w jedną stronę, a inne w inne. Zobacz wyżej listę „zastrzeżonych nagłówków”. W przypadku tych po prostu ustawiasz je jako właściwość. W przypadku innych faktycznie dodajesz nagłówek. Spójrz tutaj.
request.ContentType = "application/x-www-form-urlencoded"; request.Accept = "application/json"; request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);
źródło
Zasadniczo nie. To jest nagłówek http, więc rozsądne jest rzutowanie na
HttpWebRequest
i ustawienie.Referer
(jak wskazałeś w pytaniu):HttpWebRequest req = ... req.Referer = "your url";
źródło
Uwaga: to rozwiązanie będzie działać z WebClientSocket, a także z HttpWebRequest lub dowolną inną klasą, która używa WebHeaderCollection do pracy z nagłówkami.
Jeśli spojrzysz na kod źródłowy WebHeaderCollection.cs, zobaczysz, że Hinfo jest używane do przechowywania informacji o wszystkich znanych nagłówkach:
private static readonly HeaderInfoTable HInfo = new HeaderInfoTable();
Patrząc na klasę HeaderInfoTable, można zauważyć, że wszystkie dane są przechowywane w tablicy skrótów
private static Hashtable HeaderHashTable;
Ponadto w statycznym konstruktorze HeaderInfoTable można zobaczyć, że wszystkie znane nagłówki są dodawane do tablicy HeaderInfo, a następnie kopiowane do tablicy hashy.
Ostateczne spojrzenie na klasę HeaderInfo pokazuje nazwy pól.
internal class HeaderInfo { internal readonly bool IsRequestRestricted; internal readonly bool IsResponseRestricted; internal readonly HeaderParser Parser; // // Note that the HeaderName field is not always valid, and should not // be used after initialization. In particular, the HeaderInfo returned // for an unknown header will not have the correct header name. // internal readonly string HeaderName; internal readonly bool AllowMultiValues; ... }
Tak więc, biorąc pod uwagę wszystkie powyższe, oto kod, który używa odbicia, aby znaleźć statyczną tabelę Hashtable w klasie HeaderInfoTable, a następnie zmienia każdą ograniczoną żądanie HeaderInfo wewnątrz tablicy hash, aby była nieograniczona
// use reflection to remove IsRequestRestricted from headerInfo hash table Assembly a = typeof(HttpWebRequest).Assembly; foreach (FieldInfo f in a.GetType("System.Net.HeaderInfoTable").GetFields(BindingFlags.NonPublic | BindingFlags.Static)) { if (f.Name == "HeaderHashTable") { Hashtable hashTable = f.GetValue(null) as Hashtable; foreach (string sKey in hashTable.Keys) { object headerInfo = hashTable[sKey]; //Console.WriteLine(String.Format("{0}: {1}", sKey, hashTable[sKey])); foreach (FieldInfo g in a.GetType("System.Net.HeaderInfo").GetFields(BindingFlags.NonPublic | BindingFlags.Instance)) { if (g.Name == "IsRequestRestricted") { bool b = (bool)g.GetValue(headerInfo); if (b) { g.SetValue(headerInfo, false); Console.WriteLine(sKey + "." + g.Name + " changed to false"); } } } } } }
źródło
Używam tylko:
request.ContentType = "application/json; charset=utf-8"
źródło
Możesz po prostu rzucić WebRequest na HttpWebRequest pokazane poniżej:
var request = (HttpWebRequest)WebRequest.Create(myUri);
a następnie zamiast próbować manipulować listą nagłówków, zastosuj ją bezpośrednio w żądaniu właściwości żądania.
request.Referer = "yourReferer";
Te właściwości są dostępne w obiekcie żądania.
źródło