针对 net461,HttpClient 在 GET 请求有内容时抛出 ex,但适用于 netstandard2.0
Targeting net461, HttpClient throws ex when GET request has content, but works with netstandard2.0
我需要使用第 3 方网站 api。
在这个特定端点上,我需要使用内容正文 (json) 发出 GET 请求。
var jsonPayload = JsonConvert.SerializeObject(myObject);
var request = new HttpRequestMessage(HttpMethod.Get, endpoint)
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
};
var client = new HttpClient();
var response = await client.SendAsync(request); //<-- explodes with net461,
//but works with netstandard2.0
var responseContent = await response.Content.ReadAsStringAsync();
我将该代码定位到 netstandard2.0
,它起作用了。
但是,我现在需要在我以 net461
为目标的项目中使用,它会抛出异常“Cannot send a content-body with this verb-type”
我知道设置内容GET请求是不常见的,但是api我做不到。
- 为什么当我定位
net461
时 HttpClient.Send(request)
失败,但当我定位 netstandard2.0
时却运行良好?
- 当我定位
net461
时,我有哪些选择?
更新
一种复制方式。
ConsoleApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <!-- toggle this to net461 -->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Net.Http" />
</ItemGroup>
</Project>
Program.cs
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var jsonPayload = JsonConvert.SerializeObject(new { });
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.whosebug.com")
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json")
};
var client = new HttpClient();
var response = client.SendAsync(request).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseContent);
}
}
}
dotnet --version
显示 2.1.104
你没有提到你 运行 它在哪个 .net 版本上工作(因为你可以针对网络标准但你不能 运行净标准)。所以我假设当它在 .NET Core 上工作时 运行,当它不工作时 运行 在完整的 .NET 4.6.1 上,如你所说。
那只是因为它在 .NET Core 和完整的 .NET Framework 中的实现方式不同,如本 issue 中所述。两种实现都没有错,因为 RFC 说:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
因此,在 GET 中包含正文(虽然几乎从来不是一个好的做法)本身并不与 RFC 相矛盾。一种实现(较旧的)旨在拒绝它,但另一种(较新的)旨在允许它,仅此而已。
关于你的第二个问题"What options do I have when I target net461"。我认为没有简单的解决方法,因为那是 HttpWebRequest
的行为,而不是 HttpClient
的行为。几乎任何发出网络请求的东西都在内部使用 HttpWebRequest
。
虽然有丑陋的黑客使用反射。您的示例可以这样修改(仅当 运行ning 在完整的 .NET 上有效):
static void Main(string[] args) {
// UGLY HACK!
var verbType = typeof(HttpWebRequest).Assembly.GetType("System.Net.KnownHttpVerb");
var getMethodField = verbType.GetField("Get", BindingFlags.Static | BindingFlags.NonPublic);
var getMethod = getMethodField.GetValue(null);
verbType.GetField("ContentBodyNotAllowed", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(getMethod, false);
var jsonPayload = JsonConvert.SerializeObject(new { });
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.whosebug.com")
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json")
};
var client = new HttpClient();
var response = client.SendAsync(request).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseContent);
}
基本上我们使用反射将 KnownHttpVerb.Get
的名为 ContentBodyNotAllowed
的内部字段修改为 false。使用风险自负。
我需要使用第 3 方网站 api。
在这个特定端点上,我需要使用内容正文 (json) 发出 GET 请求。
var jsonPayload = JsonConvert.SerializeObject(myObject);
var request = new HttpRequestMessage(HttpMethod.Get, endpoint)
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
};
var client = new HttpClient();
var response = await client.SendAsync(request); //<-- explodes with net461,
//but works with netstandard2.0
var responseContent = await response.Content.ReadAsStringAsync();
我将该代码定位到 netstandard2.0
,它起作用了。
但是,我现在需要在我以 net461
为目标的项目中使用,它会抛出异常“Cannot send a content-body with this verb-type”
我知道设置内容GET请求是不常见的,但是api我做不到。
- 为什么当我定位
net461
时HttpClient.Send(request)
失败,但当我定位netstandard2.0
时却运行良好? - 当我定位
net461
时,我有哪些选择?
更新
一种复制方式。
ConsoleApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <!-- toggle this to net461 -->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Net.Http" />
</ItemGroup>
</Project>
Program.cs
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var jsonPayload = JsonConvert.SerializeObject(new { });
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.whosebug.com")
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json")
};
var client = new HttpClient();
var response = client.SendAsync(request).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseContent);
}
}
}
dotnet --version
显示 2.1.104
你没有提到你 运行 它在哪个 .net 版本上工作(因为你可以针对网络标准但你不能 运行净标准)。所以我假设当它在 .NET Core 上工作时 运行,当它不工作时 运行 在完整的 .NET 4.6.1 上,如你所说。
那只是因为它在 .NET Core 和完整的 .NET Framework 中的实现方式不同,如本 issue 中所述。两种实现都没有错,因为 RFC 说:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
因此,在 GET 中包含正文(虽然几乎从来不是一个好的做法)本身并不与 RFC 相矛盾。一种实现(较旧的)旨在拒绝它,但另一种(较新的)旨在允许它,仅此而已。
关于你的第二个问题"What options do I have when I target net461"。我认为没有简单的解决方法,因为那是 HttpWebRequest
的行为,而不是 HttpClient
的行为。几乎任何发出网络请求的东西都在内部使用 HttpWebRequest
。
虽然有丑陋的黑客使用反射。您的示例可以这样修改(仅当 运行ning 在完整的 .NET 上有效):
static void Main(string[] args) {
// UGLY HACK!
var verbType = typeof(HttpWebRequest).Assembly.GetType("System.Net.KnownHttpVerb");
var getMethodField = verbType.GetField("Get", BindingFlags.Static | BindingFlags.NonPublic);
var getMethod = getMethodField.GetValue(null);
verbType.GetField("ContentBodyNotAllowed", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(getMethod, false);
var jsonPayload = JsonConvert.SerializeObject(new { });
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.whosebug.com")
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json")
};
var client = new HttpClient();
var response = client.SendAsync(request).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseContent);
}
基本上我们使用反射将 KnownHttpVerb.Get
的名为 ContentBodyNotAllowed
的内部字段修改为 false。使用风险自负。