当前位置:  开发笔记 > 编程语言 > 正文

使用System.Net.WebRequest时无法设置某些HTTP标头

如何解决《使用System.Net.WebRequest时无法设置某些HTTP标头》经验,为你挑选了6个好方法。

当我尝试在WebRequest对象上添加HTTP标头键/值对时,我得到以下异常:

必须使用适当的属性修改此标头

我已经尝试Headers使用Add()方法向集合中添加新值,但我仍然得到相同的异常.

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

我可以通过将WebRequest对象转换为HttpWebRequest并设置诸如的属性来解决这个问题httpWebReq.Referer ="http://stackoverflow.com",但这仅适用于通过属性公开的少数标头.

我想知道是否有办法通过请求远程资源来修改标头的更精细控制.



1> dubi..:

如果您需要简短的技术答案,请转到答案的最后一部分.

如果你想更好地了解,请全部阅读,我希望你会喜欢......


我今天也反驳了这个问题,我今天发现的是:

    以上答案都是正确的,如下:

    1.1它告诉您,您尝试添加的标头已经存在,然后您应该使用适当的属性(例如索引器)修改其值,而不是尝试再次添加它.

    1.2无论何时更改a的标头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/ HttpWebRequestclass中显式的相应属性修改它们的值.


编辑:(有用,来自评论,用户Kaido评论)

解决方法是WebHeaderCollection.IsRestricted(key)在调用add之前检查标头是否已存在或是否为restricted()


这个答案只是在没有给出问题解决方案的情况下重复例外的消息.
解决方法是在调用add之前检查标头是否已存在或受限制(WebHeaderCollection.IsRestricted(key))
"使用适当的财产修改他们的价值"说明了一切
@Sam阅读1.1节解决了这个问题.这意味着我们试图通过`Headers.Add()`添加的属性已经存在,因此我们应该修改它.
"我觉得指出这个限制是.NET Framework的一个特性很重要" - 我宁愿没有这种功能.
这个答案说了很多,但没有说明如何实际设置OP想要设置的标题.

2> 小智..:

我用自定义Web客户端遇到了这个问题.我认为人们可能会因为多种方式而感到困惑.使用时,WebRequest.Create()您可以强制转换为an 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();


请注意,这个答案包含一个愉快的假设,即您正在使用桌面.Net运行时并请求http.WebRequest.Create可以返回各种不同的对象,具体取决于您使用的协议前缀.它与CustomProtocolHandlers有关,如果有人对它们感兴趣的话.在WP7或Silverlight上,请求实现类也有点不同.小心这个.

3> Despertar..:

以前的所有答案都没有提供解决方案来描述问题.这是一个扩展方法,通过允许您通过其字符串名称设置任何标头来解决此问题.

用法

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 HeaderProperties = new Dictionary(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.

另一个示例是HTTP代理,您需要在请求中获取标头并将其转发给收件人.

还有很多其他场景,它只是不实用或不可能使用属性.强制用户通过属性设置标题是一种非常不灵活的设计,这就是为什么需要反射的原因.从好的方面来说,反射是抽象的,它仍然很快(在我的测试中为.001秒),并且作为一种扩展方法感觉很自然.

笔记

根据RFC,标题名称不区分大小写,http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2



4> jvenema..:

无论何时更改a的标头HttpWebRequest,都需要在对象本身上使用适当的属性(如果存在).如果你有平原WebRequest,一定要把它扔到HttpWebRequest第一个.然后Referrer在您的情况下可以通过访问((HttpWebRequest)request).Referrer,因此您不需要直接修改标题 - 只需将属性设置为正确的值.ContentLength,ContentType,UserAgent,等等,都需要这样设置.

恕我直言,这是MS部分的一个缺点...设置标题通过Headers.Add()应该在幕后自动调用相应的属性,如果这是他们想要做的.



5> Mike Gledhil..:

当我的代码试图像这样设置"Accept"标头值时,我遇到了同样的异常:

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



6> FOR..:

WebRequest是抽象的(因为任何继承类都必须覆盖Headers属性)..您使用的是哪个具体的WebRequest?换句话说,如何让WebRequest对象与之对齐?

ehr ..我的回答让我意识到你得到的错误信息实际上是正确的:它告诉你你想要添加的标题已经存在,然后你应该使用适当的属性修改它的值(例如索引器) ),而不是试图再次添加它.这可能就是你所寻找的.

继承自WebRequest的其他类可能具有包装某些标头的更好的属性; 比如看这篇文章.

推荐阅读
mobiledu2402851373
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有