如何使用HttpClient发送GET请求body中的内容?

问题描述 投票:0回答:6

目前,为了向 API 接口发送参数化 GET 请求,我正在编写以下代码:

api/master/city/filter?cityid=1&citycode='ny'

但我发现 URL 长度有 2,083 个字符的限制。

为了避免这种情况,我想在 GET 请求的内容正文中以 json 格式发送参数。

但是,我发现 HttpClient 的 Get 方法都不允许发送内容正文。对于 POST,我可以看到 HttpClient 中有一个名为 PostAsync 的方法,它允许内容正文。

有没有办法发送不在 URL 中的 GET 请求参数,以避免 URL 长度限制?

c# get request dotnet-httpclient
6个回答
110
投票

请阅读本答案末尾的警告,了解为什么一般不建议使用带有正文的 HTTP GET 请求。


  • 如果您使用 .NET Core,标准

    HttpClient
    可以开箱即用地执行此操作。例如,要发送带有 JSON 正文的 GET 请求:

      HttpClient client = ...
    
      ...
    
      var request = new HttpRequestMessage
      {
          Method = HttpMethod.Get,
          RequestUri = new Uri("some url"),
          Content = new StringContent("some json", Encoding.UTF8, MediaTypeNames.Application.Json /* or "application/json" in older versions */),
      };
    
      var response = await client.SendAsync(request).ConfigureAwait(false);
      response.EnsureSuccessStatusCode();
    
      var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    
  • .NET Framework 不支持这种现成的(如果您尝试上述代码,您将收到

    ProtocolViolationException
    )。值得庆幸的是,Microsoft 提供了 System.Net.Http.WinHttpHandler 软件包,支持该功能 - 只需在构建 HttpClientHandler 实例时安装并使用它,而不是默认的
    HttpClient

    var handler = new WinHttpHandler(); var client = new HttpClient(handler); <rest of code as above>
    参考:

    https://github.com/dotnet/runtime/issues/25485#issuecomment-467261945


注意事项:

    带有正文的 HTTP GET 是一种有点非常规的构造,属于 HTTP 规范的灰色区域 - 最终结果是许多旧软件要么根本无法处理这样的请求,要么会明确拒绝它,因为它们相信它变得畸形。您需要非常确保您尝试发送此类请求的端点确实支持它,否则最多您会收到一个 HTTP 错误代码;最坏的情况下,尸体会被默默地丢弃。这可能会导致一些令人头疼的调试!
  • 缓存代理服务器(特别是较旧的代理服务器)可能仅根据 URL 缓存 GET 请求,因为它们不希望存在正文。这可能会导致最近的请求被永久缓存(这将破坏您的软件),或者唯一缓存的请求是最近发出的请求(这将阻止缓存按预期工作)。同样,弄清楚这一点可能会非常痛苦。

33
投票
我无法使用.NET core,也不想安装

System.Net.Http.WinHttpHandler

,它有大量的依赖项。
我通过使用反射解决了这个问题,欺骗 
WebRequest
 使用 GET 请求发送正文是合法的(根据最新的 RFC)。我所做的是将 HTTP 动词“GET”的 
ContentBodyNotAllowed
 设置为 false。

var request = WebRequest.Create(requestUri); request.ContentType = "application/json"; request.Method = "GET"; var type = request.GetType(); var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request); var methodType = currentMethod.GetType(); methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false); using (var streamWriter = new StreamWriter(request.GetRequestStream())) { streamWriter.Write("<Json string here>"); } var response = (HttpWebResponse)request.GetResponse();

但请注意,属性 
ContentBodyNotAllowed

属于静态字段,因此当其值发生更改时,它对程序的其余部分仍然有效。对于我的目的来说这不是问题。

    


2
投票

var request = WebRequest.Create(requestUri); System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; request.ContentType = "application/json"; request.Method = "GET"; request.Headers.Add("Authorization", "Bearer " + Token); var type = request.GetType(); var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request); var methodType = currentMethod.GetType(); methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false); using (var streamWriter = new StreamWriter(request.GetRequestStream())) { streamWriter.Write(JsonConvert.SerializeObject(Entity)); } var response = request.GetResponse(); var responseStream = response.GetResponseStream(); if (responseStream != null) { var myStreamReader = new StreamReader(responseStream, Encoding.Default); var resultEntity= myStreamReader.ReadToEnd(); myStreamReader.ReadToEnd()); } responseStream.Close(); response.Close();



0
投票
HttpClient

WebRequest
工作,显然服务器没有获取我的数据,并且返回一个错误,指出我的某些特定数据不可用要求。最后只有
RestSharp
在我的例子中起作用(变量
myData
是以下代码中的
Dictionary<string,string>
实例):
var client = new RestClient("some url");
var request = new RestRequest(Method.GET);
foreach (var d in myData)
    request.AddParameter(d.Key, d.Value);
var result = (await client.ExecuteAsync(request)).Content;



0
投票

而且,如果这个错误还不够,我刚刚意识到,我的网址正在从其绝对路径中丢弃“:443”,原始字符串包含“:443”,而当我发送请求时,它会被删除。

如果有人有任何答案,我们将不胜感激。谢谢!


-2
投票

var request = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = targetUri, Content = new StringContent(payload.Payload), }; var response = await client.SendAsync(request).ConfigureAwait(false); var responseInfo = await response.Content.ReadAsStringAsync();

© www.soinside.com 2019 - 2024. All rights reserved.