System.Net.WebRequest का उपयोग करते समय कुछ HTTP हेडर सेट नहीं कर सकते


130

जब मैं किसी WebRequestवस्तु पर HTTP हेडर की / वैल्यू पेयर जोड़ने की कोशिश करता हूं, तो मुझे निम्न अपवाद मिलते हैं:

इस शीर्ष लेख को उपयुक्त संपत्ति का उपयोग करके संशोधित किया जाना चाहिए

मैंने Headersऐड () विधि का उपयोग करके संग्रह में नए मान जोड़ने की कोशिश की है, लेकिन मुझे अभी भी वही अपवाद मिलता है।

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

मैं एक HttpWebRequest के लिए WebRequest ऑब्जेक्ट को कास्टिंग करके और इस तरह के गुणों को सेट करके प्राप्त कर सकता हूं httpWebReq.Referer ="http://stackoverflow.com", लेकिन यह केवल मुट्ठी भर हेडर के लिए काम करता है जो गुणों के माध्यम से उजागर होते हैं।

मुझे पता है कि अगर वहाँ एक दूरदराज के संसाधन के लिए एक अनुरोध के साथ हेडर को संशोधित करने पर एक महीन दानेदार नियंत्रण पाने का एक तरीका है।

जवाबों:


182

यदि आपको लघु और तकनीकी उत्तर की आवश्यकता है, तो उत्तर के अंतिम भाग पर जाएं।

यदि आप बेहतर जानना चाहते हैं, तो यह सब पढ़ें, और मुझे आशा है कि आप आनंद लेंगे ...


मैंने इस समस्या को आज भी गिना, और आज मैंने जो खोजा वह यह है:

  1. उपरोक्त उत्तर सत्य हैं, जैसे:

    1.1 यह आपको बता रहा है कि आप जिस हेडर को जोड़ने की कोशिश कर रहे हैं वह पहले से मौजूद है और आपको फिर से जोड़ने की कोशिश करने के बजाय उचित संपत्ति (इंडेक्सर, उदाहरण के लिए) का उपयोग करके इसके मूल्य को संशोधित करना चाहिए।

    1.2 जब भी आप किसी के हेडर को बदल रहे हैं HttpWebRequest, तो आपको ऑब्जेक्ट पर उचित गुणों का उपयोग करने की आवश्यकता है, यदि वे मौजूद हैं।

अग्रणी दिशानिर्देशों के लिए धन्यवाद और Jvenema ...

  1. लेकिन, मुझे जो पता चला, और वह पहेली में गायब था वह है:

    2.1 WebHeaderCollectionकक्षा आम तौर पर WebRequest.Headers या WebResponse.Headers के माध्यम से एक्सेस की जाती है। कुछ सामान्य शीर्षलेखों को प्रतिबंधित माना जाता है और उन्हें या तो एपीआई (जैसे सामग्री-प्रकार) द्वारा सीधे उजागर किया जाता है या सिस्टम द्वारा संरक्षित किया जाता है और बदला नहीं जा सकता है।

प्रतिबंधित हेडर हैं:

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

तो, अगली बार जब आप इस अपवाद का सामना कर रहे हैं और यह नहीं जानते कि इसे कैसे हल किया जाए, तो याद रखें कि कुछ प्रतिबंधित हेडर हैं, और समाधान उनके मूल्यों को WebRequest/ HttpWebRequestवर्ग से स्पष्ट रूप से उपयुक्त संपत्ति का उपयोग करके संशोधित करना है ।


संपादित करें: (उपयोगी, टिप्पणियों से, उपयोगकर्ता Kaido द्वारा टिप्पणी )

समाधान यह देखने के लिए है WebHeaderCollection.IsRestricted(key)कि क्या कॉल जोड़ने से पहले हेडर पहले से ही प्रतिबंधित है या ( ) है


8
"उपयुक्त संपत्ति का उपयोग करके उनके मूल्यों को संशोधित करें" यह सब कहता है
2

76
यह उत्तर समस्या का समाधान दिए बिना केवल अपवादों के संदेश को दोहरा रहा है।
000

11
समाधान यह जांचने के लिए है कि क्या हेडर पहले से मौजूद है या नहीं (WebHeaderCollection.IsRestricted (key)) कॉल करने से पहले ऐड
Kaido

7
@Sam ने खंड 1.1 पढ़ा जो इस मुद्दे को हल करता है। इसका मतलब है कि जिस संपत्ति को हम Headers.Add()पहले से ही जोड़ने की कोशिश कर रहे हैं, इसलिए हमें इसके बजाय इसे संशोधित करना चाहिए।
जुनैद कादिर

4
"मुझे लगता है कि यह बताना महत्वपूर्ण है कि यह प्रतिबंध .NET फ्रेमवर्क की एक विशेषता है" - मेरे पास इस तरह की सुविधा नहीं है।
हेबरथ अमरल

76

मैं एक कस्टम वेब क्लाइंट के साथ इस समस्या में भाग गया। मुझे लगता है कि ऐसा करने के कई तरीकों के कारण लोग भ्रमित हो सकते हैं। जब 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();

1
Ex 1 ने मेरी समस्या को इस अपवाद के साथ हल किया। इसलिए मैंने क्लाइंट को बदल दिया।हेडर्स ["रेफर"] = url; ग्राहक के लिए। Headers.Add ("रेफर", url); और चीजें काम कर रही हैं। धन्यवाद।
000

2
सावधान रहें कि इस उत्तर में एक सुखद धारणा है कि आप डेस्कटॉप .Net रनटाइम पर काम कर रहे हैं और http के लिए पूछ रहे हैं। WebRequest.Create आपके द्वारा उपयोग किए जाने वाले प्रोटोकॉल उपसर्ग के आधार पर विभिन्न वस्तुओं की एक किस्म लौटा सकता है। यह CustomProtocolHandlers से संबंधित है अगर किसी को उनमें दिलचस्पी है .. और WP7 या सिल्वरलाइट पर अनुरोध कार्यान्वयन कक्षाएं थोड़ी अलग भी हैं। बस इससे सावधान रहें।
quetzalcoatl

1
लेकिन मैं "स्वीकार" हेडर को संशोधित नहीं कर सकता। मैं इसे कैसे संशोधित कर सकता हूं?
उपयोगकर्ता

पहला उदाहरण अभी भी मुझे वही त्रुटि दे रहा है
mr

29

पिछले सभी जवाब एक समाधान प्रदान किए बिना समस्या का वर्णन करते हैं। यहाँ एक विस्तार विधि है जो किसी समस्या को हल करने की अनुमति देता है जिससे आप इसके स्ट्रिंग नाम के माध्यम से किसी भी हेडर को सेट कर सकते हैं।

प्रयोग

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 प्रॉक्सी है जहां आपको हेडर को एक अनुरोध में लेने और प्राप्तकर्ता को अग्रेषित करने की आवश्यकता है।

कई अन्य परिदृश्य हैं जहाँ इसके गुणों का उपयोग करना व्यावहारिक या संभव नहीं है। उपयोगकर्ता को संपत्ति के माध्यम से हेडर सेट करने के लिए मजबूर करना एक बहुत ही अनम्य डिजाइन है जिसके कारण प्रतिबिंब की आवश्यकता होती है। अप-साइड यह है कि प्रतिबिंब दूर है, यह अभी भी तेज है (मेरे परीक्षण में .001 दूसरा), और एक विस्तार के रूप में यह स्वाभाविक है।

टिप्पणियाँ

हैडर के नाम RFC के प्रति असंवेदनशील हैं, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2


मैं इसका उपयोग प्रॉक्सी-कनेक्शन के लिए करता हूं, लेकिन यह कहने के बाद, हां मेरे पास "प्रॉक्सी-कनेक्शन" के लिए कुंजी है, यह वापस शून्य है, जो शून्य संदर्भ अपवाद को जन्म देता है
deadManN

चतुर तय करने के लिए धन्यवाद। मैंने एक्सटेंशन को सभी हेडर सेट कर दिए: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

जब मेरे कोड ने इस तरह "हेडर" हेडर मान सेट करने का प्रयास किया तो मेरे पास समान अपवाद था:

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

12

कभी भी आप किसी के हेडर को बदल रहे हैं HttpWebRequest, आपको ऑब्जेक्ट पर उचित गुणों का उपयोग करने की आवश्यकता है, यदि वे मौजूद हैं। यदि आपके पास एक मैदान है WebRequest, तो इसे HttpWebRequestपहले डालना सुनिश्चित करें । फिर Referrerआपके मामले में के माध्यम से पहुँचा जा सकता है ((HttpWebRequest)request).Referrer, इसलिए आपको सीधे हेडर को संशोधित करने की आवश्यकता नहीं है - बस संपत्ति को सही मूल्य पर सेट करें। ContentLength, ContentType, UserAgent, आदि, सभी की जरूरत है इस तरह से सेट किया जा करने के लिए।

IMHO, यह एमएस भाग पर एक कमी है ... के माध्यम से हेडर की स्थापना Headers.Add()स्वचालित रूप से पर्दे के पीछे उपयुक्त संपत्ति को कॉल करना चाहिए, अगर यही वे करना चाहते हैं।


7

WebRequest अमूर्त होने के कारण (और किसी भी अंतर्निहित वर्ग को हेडर की संपत्ति को ओवरराइड करना चाहिए) .. आप किस ठोस WebRequest का उपयोग कर रहे हैं? दूसरे शब्दों में, आप उस WebRequest ऑब्जेक्ट को किस प्रकार प्राप्त कर सकते हैं?

ehr .. mnour उत्तर ने मुझे एहसास दिलाया कि जो त्रुटि संदेश आपको मिल रहा था, वह वास्तव में हाजिर था: यह आपको बता रहा है कि जिस हेडर को आप पहले से ही जोड़ने की कोशिश कर रहे हैं और आपको उसके बाद उपयुक्त संपत्ति (इंडेक्सर) का उपयोग करके उसका मान संशोधित करना चाहिए ) के बजाय इसे फिर से जोड़ने की कोशिश कर रहा है। शायद यही सब आप ढूंढ रहे थे।

WebRequest से विरासत में प्राप्त अन्य वर्गों में कुछ हेडर को लपेटकर बेहतर गुण हो सकते हैं; इस पोस्ट को उदाहरण के लिए देखें ।


दरअसल WebRequest.Create (url) एक WebRequest ऑब्जेक्ट का एक उदाहरण बनाता है।
इगल तबाचनिक

2

उपरोक्त उत्तर सभी ठीक हैं, लेकिन मुद्दे का सार यह है कि कुछ हेडर एक तरह से सेट किए जाते हैं, और अन्य अन्य तरीके सेट होते हैं। 'प्रतिबंधित हेडर' सूची के लिए ऊपर देखें। इन के लिए, आप बस उन्हें एक संपत्ति के रूप में सेट करते हैं। दूसरों के लिए, आप वास्तव में हेडर जोड़ते हैं। यहाँ देखें।

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

    request.Accept = "application/json";

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

1

मूल रूप से, नहीं। यह एक http हैडर है, इसलिए इसे डालना HttpWebRequestऔर सेट करना उचित है .Referer(जैसा कि आप प्रश्न में इंगित करते हैं):

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

1

नोट: यह समाधान WebClientSocket के साथ-साथ HttpWebRequest या किसी अन्य वर्ग के साथ काम करेगा जो हेडर के साथ काम करने के लिए WebHeaderCollection का उपयोग करता है।

यदि आप WebHeaderCollection.cs के स्रोत कोड को देखते हैं, तो आप देखेंगे कि Hinfo का उपयोग सभी ज्ञात हेडर की जानकारी रखने के लिए किया जाता है:

private static readonly HeaderInfoTable HInfo = new HeaderInfoTable();

HeaderInfoTable वर्ग को देखते हुए, आप देख सकते हैं कि सभी डेटा हैश तालिका में संग्रहीत हैं

private static Hashtable HeaderHashTable;

इसके अलावा, HeaderInfoTable के स्टैटिक कंस्ट्रक्टर में, आप देख सकते हैं कि सभी ज्ञात हेडर को HeaderInfo एरे में जोड़ा जाता है और फिर हैशटेबल में कॉपी किया जाता है।

हैडरइन्फो वर्ग में अंतिम रूप खेतों के नाम दिखाता है।

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

तो, उपरोक्त सभी के साथ, यहाँ एक कोड है जो HeaderInfoTable क्लास में स्थिर हैशटेबल को खोजने के लिए प्रतिबिंब का उपयोग करता है और फिर अप्रतिबंधित होने के लिए हैश तालिका के अंदर हर अनुरोध-प्रतिबंधित HeaderInfo को बदल देता है।

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

                        }
                    }

                }
            }
        } 

प्रतिभाशाली! इससे वेब सॉकेट सेट करते समय उपयोग किए गए अनुरोध के लिए उन हेडर को सेट करना संभव हो जाता है और इस तरह इस मुद्दे के आसपास काम करना होता है: github.com/dotnet/corefx/issues/26627
eystein Kolsrud

यह मामला होना चाहिए क्योंकि वे सभी हेडर में हेरफेर करने के लिए WebHeaderCollection का उपयोग करते हैं। मैंने इसे केवल HttpWebRequest पर परीक्षण किया है।
स्लीपर


0

आप बस WebRequest को नीचे दिखाए गए HttpWebRequest में डाल सकते हैं:

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

और फिर हेडर सूची में हेरफेर करने की कोशिश करने के बजाय, इसे सीधे अनुरोध संपत्ति अनुरोध में लागू करें। संदर्भ:

request.Referer = "yourReferer";

ये गुण अनुरोध ऑब्जेक्ट में उपलब्ध हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.