c# - 以 net461 为目标,当 GET 请求有内容时,HttpClient 会抛出 ex,但适用于 netstandard2.0
问题描述
我需要使用 3rd 方 web 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
它并抛出异常说“无法发送具有此动词类型的内容主体”
我知道将内容设置为 GET 请求是不常见的,但该 api 超出了我的范围。
- 为什么
HttpClient.Send(request)
我瞄准时失败net461
,但我瞄准时效果很好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>
程序.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.stackoverflow.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 中的实现方式不同,如本期所述。这两种实现都没有错,因为 RFC 说:
GET 请求消息中的有效负载没有定义的语义;
在 GET 请求上发送有效负载正文可能会导致某些现有
实现拒绝该请求。
因此,在 GET 中包含 body(虽然几乎从来都不是一个好的做法)本身并不与 RFC 相矛盾。一种实现(较旧的)旨在拒绝它,但另一种(较新的)旨在允许它,仅此而已。
至于你的第二个问题“当我瞄准 net461 时我有什么选择”。我认为没有简单的解决方法,因为这是 的行为HttpWebRequest
,而不是具体的HttpClient
. 几乎所有发出 Web 请求的东西都在HttpWebRequest
内部使用。
虽然有一些使用反射的丑陋黑客。您的示例可以这样修改(仅在完整的 .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.stackoverflow.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);
}
ContentBodyNotAllowed
基本上,我们使用反射将名为of 的内部字段修改KnownHttpVerb.Get
为 false。使用风险自负。
推荐阅读
- pyspark - IllegalArgumentException: u'Data type StringType of column is not supported
- c# - 使用 LINQ 从字符串列表中提取重叠子字符串
- laravel - 查询返回数据库中的所有项目
- ide - 如何右键单击 PyCharm 显示最近的项目?
- sparql - SPARQL 的 MarkLogic 内存限制?
- angular - 以角度 6 在页面加载时将父数据共享给不同的组件
- python-3.x - 使用 Python 3 和 RoboBrowser 向 facebook 提交表单并获取 UnicodeDecodeError
- sql - “.”处或附近的 PostgreSQL 语法错误
- excel-formula - 外部工作簿中特定值的 CountA 函数
- javafx - 给一个折线图 XAxis 学月顺序