我又踩坑了!如何为 HttpClient 请求设置 Content-Type 标头?

2020 年 10 月 12 日 CSDN
作者 | 小码甲
来源 |  Dotnet Plus (ID nodotnet)
头图 |  CSDN 下载自东方IC
最近在重构认证代码,认证过程相当常规:
POST   /open-api/v1/user-info?client_id&timstamp&rd=12345&sign=***&method=hmac
content-type: application/json
payload: { "token":"AA2917B0-C23D-40AB-A43A-4C4B61CC7C74"}

平台显示 :签名校验失败, 排查到平台收到的 Post Payload 并非预期,阅读本文,解锁正确使用 Content-Type 标头的姿势。


入坑


下面是构造 HttpClient 对象、发起请求的代码:

// 初始化HttpClientFactory
context.Services.AddHttpClient("platform", c =>
{
    c.BaseAddress = new Uri("https://alpha-engage.demohost.com/");
    c.DefaultRequestHeaders.Accept
    .Add(new MediaTypeWithQualityHeaderValue("application/json"));
})...

// 产生命名HttpClient,发起请求
 var client = _clientFactory.CreateClient("platform");
 var response = await client.PostAsync($"open-api/v1/user-token/info?{req.AuthString()}",new StringContent(req.ReqPayload.ToString(),Encoding.UTF8) );

平台日志显示,收到的请求 payload:

{\"token\":\"AA2917B0-C23D-40AB-A43A-4C4B61CC7C74\"}

额,平台收到的 JSON 数据被转码了,没有识别出 JSON?


明眼人一看,HttpClient 请求没有设置 
Content-Type接收端没有识别出JSON 格式的 payload , 进行了转码,生成了错误签名。

① Content-Type是一个Entity Header,指示资源的mediaType ,可用在请求/响应中
② 代码中new StringContent(req.ReqPayload.ToString(),Encoding.UTF8) 没有指定mediaType参数,故函数会使用text/plain默认值

当我尝试添加 Content-Type 时(下面黄色背景行代码):

context.Services.AddHttpClient("platform", c =>
{
    c.BaseAddress = new Uri("https://alpha-engage.demohost.com/");
    c.DefaultRequestHeaders.Accept
         .Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
    c.DefaultRequestHeaders.Add("content-type""application/json");
})

此时抛出以下异常:

InvalidOperationException: Misused header name. Make sure request headers are used with
HttpRequestMessage, response headers with HttpResponseMessage, and
content headers with HttpContent objects. 

纳尼,HttpContent Headers 是啥?Chrome dev tools 显示只有两种Header 啊?

 

爬坑


官方资料显示:HTTP Headers 被分为如下四类:

--- 信息 举例
.NET类型
General Header 可同时作用在请求/响应中,但是与传输数据无关 Upgrade、Connection ---
Request Header 将要获取的资源或客户端本身的信息 Accept、
Authorization
HttpRequestHeaders
Response Header 响应信息 Location、ETag HttpResponseHeaders
Entity
Header
实体Body额外的信息 Content-Length、
Connection
HttpContentHeaders
Content-Type 属于 Entity Header 的一种,对应.NET 类型   HttpContent Header;
虽然Entity Header不是请求标头也不是响应标头,它们还是会包含在请求/响应标头术语中(此说法来自官方)。

所以我们在 Chrome DevTools 没有看到 Entity Headers 分组, 却常在请求/响应标头中看到 Content-Type 标头。

回到上面的异常,.NET 严格区分四种标头,所以c.DefaultRequestHeaders.Add("content-type", "application/json") 尝试将 content-type 添加到请求头,姿势不正确,.NET 提示 InvalidOperationException


填坑


给这个常规的 Post 请求设置正确的 Content-Type 标头。

方法①对 HttpRequestMessage 对象 Content 属性添加 Header

 using (var request = new HttpRequestMessage())
{
     request.Method = new HttpMethod(method);
     request.RequestUri = new Uri(url);
     request.Content = new StringContent(payload);
     request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
     var response = await _httpClient.SendAsync(request);
     return response;
}

使用 HttpClient.SendAsync(request)

方法②写入 HttpContent 时传入媒体类型

StringContent 某个重载构造函数 : 参数3 可直接设置 media type

var response = await client.PostAsync($"open-api/v1/user-token/info?{req.AuthString()}",new StringContent(req.ReqPayload.ToString(),Encoding.UTF8,"application/json") );


干货旁白


  1. 小编对于 Http 协议有知识漏洞,搬砖时一直关注 Chrome DevTools,忽略了还有 Entity Header 一说。

  2. Content-Type 这个实体标头,会出现了请求/响应标头,指示资源的媒体类型。

  3. .NTE 针对4种 HTTP Header 强化了区别,在实际开发中要区别使用。

  • https://tools.ietf.org/html/rfc2616#page-41

  • https://developer.mozilla.org/en-US/docs/Glossary/Entity_header

更多精彩推荐

300亿美元,AMD为什么要买Xilinx?

1024程序员节开源技术英雄会,参会“英雄榜”发榜

如何应对云原生之旅中的安全挑战?

采摘工人月薪十万却无人应聘,英澳农场求助 AI

还不懂Redis?看完这个故事就明白了!

区块链+生鲜:杜绝“偷梁换柱”和“以次充好”
  
  
    
点分享
点点赞
点在看
登录查看更多
0

相关内容

【2020新书】C++20快速语法参考,第4版,209页pdf
专知会员服务
71+阅读 · 2020年8月5日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
56+阅读 · 2020年6月26日
商业数据分析,39页ppt
专知会员服务
157+阅读 · 2020年6月2日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
68+阅读 · 2020年1月17日
【书籍推荐】简洁的Python编程(Clean Python),附274页pdf
专知会员服务
173+阅读 · 2020年1月1日
C# 10分钟完成百度人脸识别
DotNet
3+阅读 · 2019年2月17日
百度开源项目OpenRASP快速上手指南
黑客技术与网络安全
5+阅读 · 2019年2月12日
DiscuzX 3.4 Phar反序列化漏洞
黑客工具箱
8+阅读 · 2019年1月4日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
已删除
将门创投
4+阅读 · 2018年7月31日
教你用Python爬虫股票评论,简单分析股民用户情绪
数据派THU
10+阅读 · 2017年12月12日
构建离线web应用(二)
前端黑板报
3+阅读 · 2017年12月7日
Arxiv
0+阅读 · 2020年12月1日
Arxiv
0+阅读 · 2020年12月1日
Arxiv
0+阅读 · 2020年12月1日
Arxiv
24+阅读 · 2020年3月11日
VIP会员
相关资讯
C# 10分钟完成百度人脸识别
DotNet
3+阅读 · 2019年2月17日
百度开源项目OpenRASP快速上手指南
黑客技术与网络安全
5+阅读 · 2019年2月12日
DiscuzX 3.4 Phar反序列化漏洞
黑客工具箱
8+阅读 · 2019年1月4日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
已删除
将门创投
4+阅读 · 2018年7月31日
教你用Python爬虫股票评论,简单分析股民用户情绪
数据派THU
10+阅读 · 2017年12月12日
构建离线web应用(二)
前端黑板报
3+阅读 · 2017年12月7日
Top
微信扫码咨询专知VIP会员