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

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

我尝试过添加新值 Headers 使用 Add() 方法进行集合,但我仍然得到相同的异常。

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

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

我想知道是否有一种方法可以通过对远程资源的请求来更细粒度地控制修改标头。

有帮助吗?

解决方案

如果您需要简短且技术性的答案,请直接阅读答案的最后一部分。

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


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

  1. 上述答案均正确,如下:

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

    1.2 任何时候你改变一个文件的标题 HttpWebRequest, ,您需要使用对象本身的适当属性(如果存在)。

感谢 FOR 和 Jvenema 的指导方针......

  1. 但是,我发现了什么,以及 这就是拼图中缺失的一块 就是它:

    2.1 的 WebHeaderCollection 类通常通过以下方式访问 WebRequest.标题或 WebResponse.标题。 一些常见标头被认为是受限制的,要么直接由 API 公开(例如 Content-Type),要么受系统保护且无法更改。

受限制的标头是:

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

因此,下次您遇到此异常并且不知道如何解决此问题时,请记住有一些受限制的标头,解决方案是使用适当的属性显式修改它们的值 WebRequest/HttpWebRequest 班级。


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

解决方案是检查标头是否已存在或受到限制(WebHeaderCollection.IsRestricted(key)) 在调用 add 之前

其他提示

我使用自定义Web客户端遇到了这个问题。我认为人们可能会因为多种方式而感到困惑。使用WebRequest.Create()时,您可以转换为HttpWebRequest并使用该属性添加或修改标题。使用WebHeaderCollection时,您可以使用.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();

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

<强>用法

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

无论何时更改HttpWebRequest的标题,都需要在对象本身上使用适当的属性(如果存在)。如果您有一个简单的WebRequest,请务必先将其转换为Referrer。然后可以通过((HttpWebRequest)request).Referrer访问ContentLength,因此您无需直接修改标题 - 只需将属性设置为正确的值即可。 ContentTypeUserAgentHeaders.Add()等都需要这样设置。

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

当我的代码尝试设置<!>“接受<!>”时,我遇到了同样的异常;标头值如下:

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

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

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

从WebRequest继承的其他类可能包含更好的属性包装某些标头;见这篇文章

上面的答案都很好,但问题的实质是某些标题是单向设置的,而其他标题是以其他方式设置的。请参阅上面的“受限标题”列表。对于这些,您只需将它们设置为属性即可。对于其他人,您实际上添加了标题。见这里。

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

    request.Accept = "application/json";

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

基本上没有。这是一个http标头,因此转换为HttpWebRequest并设置.Referer(正如您在问题中指出的那样)是合理的:

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

我正在使用:

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

您可以将WebRequest强制转换为下面显示的HttpWebRequest:

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

然后不是试图操纵标题列表,而是直接在请求属性请求中应用它。引用:

request.Referer = "yourReferer";

请求对象中提供了这些属性。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top