HttpRequestMessage的Content-Type头部的奇怪行为

16 浏览
0 Comments

HttpRequestMessage的Content-Type头部的奇怪行为

我尝试使用C#(.NET Core 2.2.104)向外部 Web 服务发送带有 application/json 格式的请求体的 HTTP POST 请求。我已经阅读了 Stack Overflow 上所有类似的问题,并编写了以下代码:

SignXmlRequestDto requestBody = new SignXmlRequestDto(p12, model.SignCertPin, model.Data);
string json = JsonConvert.SerializeObject(requestBody);
var httpRequestMessage = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = ncanNodeUrl,
    Headers =
    {
        { HttpRequestHeader.ContentType.ToString(), "application/json" }
    },
    Content = new StringContent(JsonConvert.SerializeObject(json))
};
var response = await httpClient.SendAsync(httpRequestMessage);
string responseString = await response.Content.ReadAsStringAsync();

我从服务端收到了一个错误,错误信息是:“无效的 Content-Type 标头,请将 Content-Type 设置为 application/json”。有趣的是,如果我使用 Postman 模拟该请求,一切都正常,并且我收到了成功的响应。[点击此处查看截图](https://i.stack.imgur.com/4SBm5.png)

更新:根据 @Kristóf Tóth 的建议,我修改了代码如下:

var httpRequestMessage = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = ncanNodeUrl,
    Content = new StringContent(json, Encoding.UTF8, "application/json")
};
var response = await httpClient.SendAsync(httpRequestMessage);
string responseString = await response.Content.ReadAsStringAsync();

但是仍然收到了相同的错误消息。

0
0 Comments

问题的出现原因是Content-Type头部未被正确设置。解决方法是使用JsonContent代替StringContent,并将内容序列化为JSON字符串后再进行包装。具体方法如下:

// 将内容序列化为JSON字符串
var stringPayload = JsonConvert.SerializeObject(payload);
// 使用HttpClient类对JSON字符串进行包装,设置Content-Type为application/json
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");

另外,也某些情况下这种方法无法解决问题,仍然出现相同的错误。而有人回答说这是HTTP POST请求的正确方法,如果这种方法不起作用,那么在HttpClient发布4年后人们应该已经注意到了。

0
0 Comments

从上面的内容中可以整理出以下问题的原因和解决方法:

问题原因:

问题出现在HttpRequestMessage的Content-Type头部。Content-Type应该设置在内容上,而不是请求本身。通过设置StringContent的Headers.ContentType属性可以解决这个问题。但是使用StringContent的构造函数设置Content-Type并没有起作用。

解决方法:

可以通过以下两种方法来设置Content-Type:

1. 使用StringContent的构造函数:

Content = new StringContent(JsonConvert.SerializeObject(json),Encoding.UTF8, "application/json")

2. 设置StringContent的Headers.ContentType属性:

var content=new StringContent(JsonConvert.SerializeObject(json));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

在这里,第二种方法解决了问题。但是为什么第一种方法没有起作用呢?通过使用Fiddler来检查有什么不同。Postman可以帮助手动创建HTTP请求,但无法显示实际发送或接收的内容。Fiddler可以捕获两者。

此外,还需要注意使用的.NET版本和通过NuGet包添加的HttpClient。通过构造函数传递Content-Type非常常见,所以人们应该已经注意到了。可能存在某些隐秘的错误组合,例如在特定的HttpClient版本或.NET Core运行时中,但这仍然是非常不可能的。

作者使用的是.NET Core 2.2.104版本,并尝试使用了stackoverflow上的代码,但并没有解决问题。

0