如何用HttpClient在GET请求中发送内容?

问题描述 投票:21回答:3

目前,为了向一个API接口发送一个参数化的GET请求,我写了以下代码。

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

但我看到URL的长度有限制,为2,083个字符。

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

然而,我看到HttpClient的Get方法都不允许发送内容体。对于POST,我看到HttpClient中有一个名为PostAsync的方法允许发送内容体。

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

c# get request dotnet-httpclient
3个回答
41
投票

请阅读本答案最后的注意事项,为什么一般不建议使用带body的HTTP GET请求。


  • 如果你使用的是.NET 核心技术,标准 HttpClient 可以做到这一点。例如,发送一个带有JSON体的GET请求。

    HttpClient client = ...
    
    ...
    
    var request = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri("some url"),
        Content = new StringContent("some json", Encoding.UTF8, ContentType.Json),
    };
    
    var response = await client.SendAsync(request).ConfigureAwait(false);
    response.EnsureSuccessStatusCode();
    
    var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    
  • .NET 架構 不支持这个开箱即用的功能(你会收到一个 ProtocolViolationException 如果你尝试上述代码)。) 值得庆幸的是,微软已经提供了 System.Net.Http.WinHttpHandler。 包,该 是否 支持该功能--只需安装并使用它来代替默认的 HttpClientHandler 在构建您的 HttpClient 实例。

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

    参考文献。https:/github.comdotnetcorefxissues28135#issuecomment-467261945。


需要注意的是,带body的HTTP GET是一种非常规的结构,属于HTTP规范的灰色地带。

  • 带有body的HTTP GET是一个非常规的结构,属于HTTP规范中的灰色地带--最终的结果是,许多旧的软件要么根本无法处理这样的请求,要么会明确地拒绝它,因为他们认为它是畸形的。你需要确保你试图发送这样一个请求的终端支持它,否则最好的情况是你会得到一个HTTP错误代码,最坏的情况是主体会被默默丢弃。这可能导致一些令人头疼的调试!
  • 缓存代理服务器,尤其是较老的代理服务器,可能会只根据URL缓存GET请求,因为他们不希望有body存在。这可能会导致最近的请求永远被缓存(这会破坏你的软件),或者唯一被缓存的请求是最近发出的请求(这会阻止缓存工作)。同样,这可能是非常痛苦的问题。

4
投票

我不能使用.NET core,而且我不想安装。System.Net.Http.WinHttpHandler我通过使用反射解决了这个问题,以骗取 WebRequest 在GET请求中发送body是合法的(根据最新的RFC)。我所做的是设置 ContentBodyNotAllowed 为false,用于HTTP动词 "GET"。

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 属于一个静态字段,所以当它的值发生变化时,它在程序的其余部分仍然有效。这对我的目的来说不是问题。


1
投票

类似于上面的答案,但代码较少

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.