异常处理:必须使用适当的属性或方法修改此标头

(v4.0)中,使用HttpWebRequest请求Web页面,当向HttpWebRequest的Headers的标头集合中添加Referer,Host这类HTTP标头(Header)时,会收到:System.Argument: 必须使用适当的属性或方法修改此标头。这样的报错!

这个问题的引起在官方的说法是:

通常通过 WebRequest.Headers 或 WebResponse.Headers 访问 WebHeaderCollection 类。
某些公共标头被视为受限制的,它们或者直接由 API(如 Content-Type)公开,或者受到系统保护,不能被更改。
受限制的标头是:

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

要解决这个问题可以用以下这些方法:

方法一: 通过HttpWebRequest/HttpWebResponse对象的相应属性来设置这些表头

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://blog.useasp.net/");
 request.Host = "http://blog.useasp.net/";
 request.Referer = "http://blog.useasp.net/tags/.net";

 /* 你可以在这里设置其他限制的标头. 注意: Range HTTP标头是通过AddRange来添加 If-Modified-Since HTTP标头通过IfModifiedSince 属性设置 Accept由 Accept 属性设置。 Connection由 Connection 属性和 KeepAlive 属性设置。 Content-Length由 ContentLength 属性设置。 Content-Type由 ContentType 属性设置。 Expect由 Expect 属性设置。 Date由 Date属性设置,默认为系统的当前时间。 Host由系统设置为当前主机信息。 Referer由 Referer 属性设置。 Transfer-Encoding由 TransferEncoding 属性设置(SendChunked 属性必须为 true)。 User-Agent由 UserAgent 属性设置。 */

 using((HttpWebResponse)response = (HttpWebResponse)request.GetResponse()) {
 // do something here too. by Mitchell Chu
 }

要将所有的这些受限HTTP标头在写程序的时候记住,还是有点难度的,我们更希望能够自动判定那些是可以直接添加的,哪些是需要特殊处理的。在WebHeaderCollection中有个方法IsRestricted正好是解决这个问题的。因此上面的代码可以改为将所有需要的标头添加到WebHeaderCollection,在为HttpWebRequest添加标头的时候,再使用IsRestricted来确定特殊处理与否。

foreach (string key in headers.AllKeys) {
     if (!WebHeaderCollection.IsRestricted(key))
         request.Headers.Add(key, headers[key]);
     else
     {
         // do some thing, use HttpWebRequest propertiers to add restricted http header.
     }
 }

 

方法二: 继承WebHeaderCollection,通过AddWithoutValidate方法来添加表头(此方法在v4不适合,见评论)

public class InheritWebHeaders : WebHeaderCollection {
     /*     define your properties & methods here. -- by Mitchell Chu     */
     public void AddHeaderWithoutValidate(
         string name
         , string value)
     {
         base.AddWithoutValidate(name, value);
     }
 }
  // usage: HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://blog.useasp.net/"); 
InheritWebHeaders headers = new InheritWebHeaders();
 headers.AddHeaderWithoutValidate("Referrer", "http://blog.useasp.net/tag/.net");
 // other HTTP Headers request.Headers = headers;
 /// do more here...

方法三: 好吧,暂时还没有想到,如果你知道,请分享下。。。

Tuesday, September 03, 2013 | .NET技术

文章评论

  • # re: 异常处理:必须使用适当的属性或方法修改此标头
    方法二你试过了吗?我这边还是报哪个错嘛,我看源码里Headers 的set 方法还是重新构造的WebHeaderCollection 对象,一样报错诶。
  • # re: 异常处理:必须使用适当的属性或方法修改此标头
    所有的方法测试过的,如果你会报错,可以将相关信息放出来,我们一起讨论下,看看我能不能帮到你。:-)
  • # re: 异常处理:必须使用适当的属性或方法修改此标头
    • Juge
    • 5/6/2018 3:40 PM
    方法二确实不行,一样报错
  • # re: 异常处理:必须使用适当的属性或方法修改此标头
    • FanYG
    • 11/13/2020 10:36 PM
    方法二确实不行,示例代码能通过测试,可能是因为标头Referer拼写错误,示例代码中是:Referrer
  • # re: 异常处理:必须使用适当的属性或方法修改此标头
    方法二在.NET Framework 4中无法使用,个人测试时因拼写失误导致测试结果有误。
    在官方文档中对于这个有表述:docs.microsoft.com/...
    On .NET Framework, some common headers are considered restricted and are either exposed directly by the API (such as Content-Type) or protected by the system and cannot be changed. This does not apply to .NET Core and .NET 5+, where none of the headers are restricted.
       The restricted headers are:
           Accept
           Connection
           Content-Length
           Content-Type
           Date
           Expect
           Host
           If-Modified-Since
           Range
           Referer
           Transfer-Encoding
           User-Agent
           Proxy-Connection
      
    以上这些参数被禁止修改,但在.NET Core 和v5之后将不做限制。
    BTW: Referer是Referrer的错误拼写方式。参考: https://en.wikipedia.org/wiki/HTTP_referer

发表评论

Please add 2 and 5 and type the answer here:

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。