问题 HttpWebRequest长URI解决方法?


我遇到了HttpWebRequest的问题,如果URI长度超过2048个字符,则请求失败并返回404错误,即使服务器完全能够为URI长的请求提供服务。我知道这一点,因为如果通过HttpWebRequest提交错误导致错误,直接粘贴到浏览器地址栏时工作正常。

我目前的解决方法是允许用户设置一个兼容性标志,表示将参数作为POST请求发送是安全的,而不是在URI太长的情况下,但这并不理想,因为我使用的协议是RESTful和GET应该用于查询。此外,没有任何保证协议的其他实现者将接受POSTed查询

在.Net中是否有另一个类具有与HttpWebRequest相同的功能,而不受我可以使用的URI长度限制的影响?
我知道WebClient,但我真的不想使用它,因为我需要能够完全控制WebClient限制其能力的HTTP标头。

编辑

因为Shoban要求它:

http://localhost/BBCDemo/sparql/?query=PREFIX+rdf%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%3E%0D%0APREFIX+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0D%0APREFIX+xsd%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%23%3E%0D%0APREFIX+skos%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23%3E%0D%0APREFIX+dc%3A+%3Chttp%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%3E%0D%0APREFIX+po%3A+%3Chttp%3A%2F%2Fpurl.org%2Fontology%2Fpo%2F%3E%0D%0APREFIX+timeline%3A+%3Chttp%3A%2F%2Fpurl.org%2FNET%2Fc4dm%2Ftimeline.owl%23%3E%0D%0ASELECT+*+WHERE+{%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+dc%3Atitle+%3Ftitle+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Ashort_synopsis+%3Fsynopsis-short+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Amedium_synopsis+%3Fsynopsis-med+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Along_synopsis+%3Fsynopsis-long+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Amasterbrand+%3Fchannel+.%0D%0A++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Agenre+%3Fgenre+.%0D%0A++++%3Fchannel+dc%3Atitle+%3Fchanneltitle+.%0D%0A++++OPTIONAL+{%0D%0A++++++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Abrand+%3Fbrand+.%0D%0A++++++++%3Fbrand+dc%3Atitle+%3Fbrandtitle+.%0D%0A++++}%0D%0A++++OPTIONAL+{%0D%0A++++++++%3Chttp%3A%2F%2Fwww.bbc.co.uk%2Fprogrammes%2Fb00n4d6y%23programme%3E+po%3Aversion+%3Fver+.%0D%0A++++++++%3Fver+po%3Atime+%3Finterval+.%0D%0A++++++++%3Finterval+timeline%3Astart+%3Fstart+.%0D%0A++++++++%3Finterval+timeline%3Aend+%3Fend+.%0D%0A++++}%0D%0A}&default-graph-uri=&timeout=30000

以下是编码到查询字符串的以下内容:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX po: <http://purl.org/ontology/po/>
PREFIX timeline: <http://purl.org/NET/c4dm/timeline.owl#>
SELECT * WHERE {
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> dc:title ?title .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:short_synopsis ?synopsis-short .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:medium_synopsis ?synopsis-med .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:long_synopsis ?synopsis-long .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:masterbrand ?channel .
  <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:genre ?genre .
  ?channel dc:title ?channeltitle .
  OPTIONAL {
    <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:brand ?brand .
    ?brand dc:title ?brandtitle .
  }
  OPTIONAL {
    <http://www.bbc.co.uk/programmes/b00n4d6y#programme> po:version ?ver .
    ?ver po:time ?interval .
    ?interval timeline:start ?start .
    ?interval timeline:end ?end .
  }

}


11881
2017-10-19 10:00


起源

我想看到超过2048个字符的网址;-) - Shoban
@Shoban为你添加了一个例子 - RobV


答案:


我正在使用的协议是RESTful,GET应该用于查询。

没有理由POST也不能用于查询;对于非常长的请求数据,因为非常长的URI不是全局支持的,而且从来没有。这是HTTP不符合REST理想的一个领域。

POST通常不用于普通HTML级别的原因是停止浏览器提示重新加载,并促进例如。书签。但是对于HttpWebRequest,你没有任何一个问题,所以继续发布它。 Web应用程序应使用参数或URI路径部分来区分写请求和查询,而不仅仅是请求方法。 (当然,仍应拒绝来自GET方法的写入请求。)


6
2017-10-19 10:20



是的,我查看了协议的文档,它说实现者可以支持POSTed查询,所以他们应该支持它们但是没有guarentees - RobV
+1 POST是获取长网址的方法。 - db42
从方法论和哲学的角度来看,这是无稽之谈,但它有效!谢谢。 - Pavel Shkleinik


我不认为HttpWebRequest实际上与您正在谈论的大小的GET URL不兼容。我基于两件事说这个:

  1. 在我自己的工作中,我使用HttpWebRequest发送超过2048个字符的HTTP GET请求,没有任何问题。我不确定我最长的是什么,但我们说的是10,000多个角色。 (这主要是在Web应用程序和在Tomcat下运行的Solr实例之间。)

  2. .NET确实对GET URL长度有一些限制,但我所知道的远远超过2048个字符。例如,我今天从我的分析器中了解到WebRequest.Create(string url)调用了 Uri类构造函数,如果“uriString的长度超过65534个字符”,则记录为抛出UriFormatException。

我不确定你的问题可能在哪里,如果它不是HttpWebRequest本身。您知道在什么条件下您的Web服务将返回HTTP 404(即“未找到”)? (我假设404来自你的网络服务,而不是在.NET的深处伪造。)我还想仔细检查你粘贴到浏览器中的地址实际上是同一个地址。由.NET发送;正如feroze建议的那样,你应该使用网络嗅探工具。如果这两个地址相同,那么接下来可能会比较.NET标题和浏览器案例之间HTTP标头的变化情况。 (顺便说一句,我个人觉得 提琴手 这些线路上的HTTP调试任务比wireshark更容易一些。)

另见这个有点相关的问题: HttpWebRequest与将URL粘贴到地址栏有何不同(功能)?


3
2018-02-27 02:44





这是一个构造的片段 HttpWebRequest 具有越来越大的url值的实例,直到抛出异常:

using System.Net;

...

StringBuilder url = new StringBuilder("http://example.com?p=");
try
{
    for (int i = 1; i < Int32.MaxValue; i++)
    {
        url.Append("0");
        HttpWebRequest request = HttpWebRequest.CreateHttp(url.ToString());
    }
}
catch (Exception ex)
{
    Console.Out.WriteLine("Error occurred at url length: " + url.Length);
    Console.Out.WriteLine(ex.GetType().ToString() + ": " + ex.Message);
    return;
}
Console.Out.WriteLine("Completed without error!");

在我的机器上(在运行.Net 4.5的LINQPad中),此代码段输出:

Error occurred at url length: 65520
System.UriFormatException: Invalid URI: The Uri string is too long.

2
2017-09-18 15:38





根据RFC3986,您的查询字符串是错误的。 URI中不允许使用“{”和“}”字符。


0
2017-10-17 21:17



嗯,给出的URI是由.Net生成的 Uri.EscapeDataString() 方法,不知道哪个URI RFC符合 - RobV