System.Net.WebRequest kullanılırken bazı HTTP üstbilgileri ayarlanamaz


130

Bir WebRequestnesneye HTTP başlık anahtarı / değer çifti eklemeye çalıştığımda , aşağıdaki istisnayı alıyorum:

Bu başlık, uygun özellik kullanılarak değiştirilmelidir

HeadersAdd () yöntemini kullanarak koleksiyona yeni değerler eklemeyi denedim, ancak yine de aynı istisnayı alıyorum.

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

WebRequest nesnesini bir HttpWebRequest'e çevirerek ve gibi özellikleri ayarlayarak bu sorunu aşabilirim httpWebReq.Referer ="http://stackoverflow.com", ancak bu yalnızca özellikler aracılığıyla sunulan bir avuç başlık için işe yarar.

Bir uzak kaynak talebiyle başlıkları değiştirmek için daha hassas bir denetim elde etmenin bir yolu olup olmadığını bilmek isterim.

Yanıtlar:


182

Kısa ve teknik cevaba ihtiyacınız varsa, cevabın son bölümüne gidin.

Daha iyi bilmek istiyorsanız hepsini okuyun, umarım beğenirsiniz ...


Bugün de bu soruna karşı koydum ve bugün keşfettiğim şey şudur:

  1. yukarıdaki cevaplar şu şekilde doğrudur:

    1.1 size eklemeye çalıştığınız başlığın zaten mevcut olduğunu ve daha sonra yeniden eklemeye çalışmak yerine uygun özelliği (örneğin dizin oluşturucuyu) kullanarak değerini değiştirmeniz gerektiğini söylüyor.

    1.2 Bir'in başlıklarını her değiştirdiğinizde HttpWebRequest, varsa nesnenin kendisinde uygun özellikleri kullanmanız gerekir.

Önde gelen yönergeler için FOR ve Jvenema'ya teşekkürler ...

  1. Ama bulduğum şey, bulmacadaki eksik parça şuydu :

    2.1 WebHeaderCollectionSınıfa genellikle WebRequest.Headers veya WebResponse.Headers aracılığıyla erişilir . Bazı yaygın başlıklar kısıtlanmış olarak kabul edilir ve ya doğrudan API tarafından gösterilir (İçerik Türü gibi) ya da sistem tarafından korunur ve değiştirilemez.

Kısıtlanmış başlıklar şunlardır:

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

Bu nedenle, bir dahaki sefere bu istisnayla karşılaştığınızda ve bunu nasıl çözeceğinizi bilmiyorsanız, bazı kısıtlanmış başlıklar olduğunu ve çözümün WebRequest/ HttpWebRequestsınıfından uygun özelliği kullanarak değerlerini değiştirmek olduğunu unutmayın .


Düzenleme: (yararlı, yorumlardan, Kaido kullanıcısının yorumları )

Çözüm, WebHeaderCollection.IsRestricted(key)add komutunu çağırmadan önce başlığın zaten var olup olmadığını veya kısıtlanmış ( ) olup olmadığını kontrol etmektir.


8
"uygun özelliği kullanarak değerlerini değiştirin" her
şeyi

76
Bu cevap, soruna bir çözüm getirmeden sadece istisnaların Mesajını tekrar etmektir.
000

11
Çözüm, add
Kaido

7
@Sam sorunu çözen 1.1 bölümünü okuyun. bu, aracılığıyla eklemeye çalıştığımız mülk Headers.Add()zaten var demektir, bu nedenle onu değiştirmemiz gerekir.
Junaid Kadir

4
"Bu kısıtlamanın .NET Framework'ün bir özelliği olduğunu belirtmenin önemli olduğunu düşünüyorum" - Bu tür bir özelliğe sahip olmamayı tercih ederim.
Herberth Amaral

77

Bu sorunla özel bir web istemcisiyle karşılaştım. Bence bunu yapmanın birden fazla yolu yüzünden insanların kafası karışıyor. Kullanırken WebRequest.Create()bir yayın yapabilirsiniz HttpWebRequestve eklemek veya bir başlık değiştirmek için özelliğini kullanın. Bir kullanırken WebHeaderCollectionkullanabileceğiniz .Add("referer","my_url").

Ör 1

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

Ör 2

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

1
Ex 1 bu istisna ile sorunumu çözdü. Bu yüzden istemciyi değiştirdim.Headers ["yönlendiren"] = url; client.Headers.Add ("yönlendiren", url); ve işler yoluna giriyor. Teşekkürler.
000

2
Bu cevabın, masaüstü .Net çalışma zamanında çalıştığınıza ve http istediğinize dair mutlu bir varsayım içerdiğine dikkat edin. WebRequest.Create, kullandığınız protokol önekine bağlı olarak çeşitli farklı nesneler döndürebilir. Bu, CustomProtocolHandlers ile ilgilenen herhangi biri ile ilgilidir .. WP7 veya Silverlight'ta istek uygulama sınıfları da biraz farklıdır. Sadece buna dikkat et.
quetzalcoatl

1
Ancak "Kabul Et" başlığını değiştiremiyorum. Bunu nasıl değiştirebilirim?
kullanıcı

İlk örnek hala bana aynı hatayı veriyor
mrid

29

Önceki yanıtların tümü, bir çözüm sağlamadan sorunu açıklamaktadır. Dize adı aracılığıyla herhangi bir başlığı ayarlamanıza izin vererek sorunu çözen bir uzantı yöntemi.

kullanım

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

Uzatma Sınıfı

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;
        }
    }
}

Senaryolar

İçin bir sarmalayıcı yazdım HttpWebRequestve kısıtlanmış 13 başlığın tümünü sarmalayıcımdaki özellikler olarak göstermek istemedim. Bunun yerine basit kullanmak istedim Dictionary<string, string>.

Başka bir örnek, bir istekte üstbilgiler almanız ve bunları alıcıya iletmeniz gereken bir HTTP proxy'dir.

Özelliklerin kullanılmasının pratik olmadığı veya mümkün olmadığı birçok başka senaryo var. Kullanıcıyı bir özellik aracılığıyla başlığı ayarlamaya zorlamak çok esnek olmayan bir tasarımdır ve bu nedenle yansıma gereklidir. Üst tarafı, yansımanın soyutlanmış olması, hala hızlı olması (testlerimde 0,001 saniye) ve bir uzatma yöntemi olarak doğal hissettiriyor.

notlar

Üstbilgi adları, RFC'ye göre büyük / küçük harfe duyarlı değildir, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2


onu Proxy-Connection için kullanıyorum, ancak evet
dedikten

Zekice düzeltme için teşekkürler. Uzantının tüm başlıkları ayarlamasına izin verdim: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); } } }
Suncat2000

13

Kodum "Kabul Et" başlık değerini şu şekilde ayarlamaya çalıştığında aynı istisnayı yaşadım:

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

Çözüm, bunu şu şekilde değiştirmekti:

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

12

Bir öğesinin başlıklarını her değiştirdiğinizde HttpWebRequest, varsa nesnenin kendisinde uygun özellikleri kullanmanız gerekir. Bir düzlüğünüz varsa WebRequest, onu bir HttpWebRequestilke attığınızdan emin olun . Daha sonra Referrer, sizin durumunuz üzerinden erişilebilir ((HttpWebRequest)request).Referrer, böylece başlığı doğrudan değiştirmeniz gerekmez - sadece özelliği doğru değere ayarlayın. ContentLength, ContentType, UserAgent, Vs, tüm ihtiyaç bu şekilde ayarlanmalıdır.

IMHO, bu MS bölümünde bir eksikliktir ... başlıkları ayarlamak, Headers.Add()yapmak istedikleri buysa, perde arkasındaki uygun özelliği otomatik olarak çağırmalıdır.


7

WebRequest soyuttur (ve devralan herhangi bir sınıfın Başlıklar özelliğini geçersiz kılması gerektiğinden) .. hangi somut WebRequest'i kullanıyorsunuz? Diğer bir deyişle, bu WebRequest nesnesini nasıl elde edersiniz?

ehr .. mnour cevabı, aldığınız hata mesajının gerçekten fark edildiğini fark etmemi sağladı: size eklemeye çalıştığınız başlığın zaten mevcut olduğunu ve ardından uygun özelliği (örneğin indeksleyici) kullanarak değerini değiştirmeniz gerektiğini söylüyor. ), tekrar eklemeye çalışmak yerine. Muhtemelen tüm aradığın buydu.

WebRequest'ten miras alan diğer sınıflar, belirli başlıkları saran daha da iyi özelliklere sahip olabilir; Örneğin bu gönderiye bakın .


Aslında WebRequest.Create (url), WebRequest nesnesinin bir örneğini oluşturur.
Igal Tabachnik

2

Yukarıdaki cevapların hepsi gayet iyi, ancak sorunun özü, bazı başlıkların bir yöne ayarlanması ve diğerlerinin başka yollara ayarlanmasıdır. 'Kısıtlanmış başlık' listeleri için yukarıya bakın. Bunlar için, onları bir mülk olarak ayarlarsınız. Diğerleri için aslında başlığı eklersiniz. Buraya bakın.

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

    request.Accept = "application/json";

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

1

Temelde hayır. Bu bir http üstbilgisidir, bu nedenle (soruda belirttiğiniz gibi) şuna dönüştürmek HttpWebRequestve ayarlamak mantıklıdır .Referer:

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

1

Not: Bu çözüm, WebClientSocket ile birlikte HttpWebRequest veya üstbilgilerle çalışmak için WebHeaderCollection kullanan diğer herhangi bir sınıfla da çalışacaktır.

WebHeaderCollection.cs kaynak koduna bakarsanız, Hinfo'nun bilinen tüm başlıkların bilgilerini saklamak için kullanıldığını göreceksiniz:

private static readonly HeaderInfoTable HInfo = new HeaderInfoTable();

HeaderInfoTable sınıfına bakıldığında, tüm verilerin hash tablosunda depolandığını fark edebilirsiniz.

private static Hashtable HeaderHashTable;

Ayrıca, HeaderInfoTable'ın statik yapılandırıcısında, bilinen tüm başlıkların HeaderInfo dizisine eklendiğini ve ardından hashtable'a kopyalandığını görebilirsiniz.

HeaderInfo sınıfına son bakış, alanların adlarını gösterir.

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;
    ...
    }

Dolayısıyla, yukarıdakilerin tümü ile birlikte, HeaderInfoTable sınıfında statik Hashtable'ı bulmak için yansımayı kullanan ve ardından hash tablosu içindeki her istek kısıtlamalı HeaderInfo'yu sınırsız olacak şekilde değiştiren bir kod.

        // 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");
                            }

                        }
                    }

                }
            }
        } 

Parlak! Bu ayrıca, web soketlerini kurarken ve böylece bu sorunu çözerken
Øystein Kolsrud

Durum böyle olmalıdır çünkü hepsi üstbilgileri işlemek için WebHeaderCollection kullanır. HttpWebRequest üzerinde yalnızca tho üzerinde test ettim.
Sleeper

0

Ben sadece kullanıyorum:

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

0

WebRequest'i aşağıda gösterilen bir HttpWebRequest'e çevirebilirsiniz:

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

ve sonra başlık listesini değiştirmeye çalışmak yerine, bunu doğrudan istek özelliği isteğine uygulayın.

request.Referer = "yourReferer";

Bu özellikler istek nesnesinde mevcuttur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.