1. 坑位

最近在重构认证代码,认证过程相当常规:

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标头的姿势。

2. 步步为营

下面是构造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,接收端没有识别出payload是JSON,接收时进行了转码,生成了错误签名。

① Content-Type是一个Entity Header,指示资源的media type ,可用在请求或者响应中。

② 以上代码中new StringContent(req.ReqPayload.ToString(),Encoding.UTF8)指定了Encoding=UTF-8,却没有指定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啊?

3. 爬坑

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

--- 信息 举例 对应.NET类型
General Header 可同时作用在请求/响应中,但是与传输数据无关 Upgrade、Connection ---
Request Header 将要获取的资源或客户端本身的信息 Accept、Authorization System.Net.Http.Headers.HttpRequestHeaders
Response Header 响应信息 Location、ETag System.Net.Http.Headers.HttpResponseHeaders
Entity Header 实体Body额外的信息 Content-Length、Content-Type System.Net.Http.Headers.HttpContentHeaders

Content-Type属于Entity Header中的一种。

即便Entity Header既不是请求标头也不是响应标头,它们还是会包含在请求/响应标头术语中(此说法来自官方)。

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

回到上面的异常,.NET 严格区分四种标头,所以我上面

c.DefaultRequestHeaders.Add("content-type", "application/json");尝试在请求头添加Content-Type标头, 姿势错误, .NET会提示InvalidOperationException异常。

4. 填坑

给这个常规的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)

② 对StringContent重载构造函数传参

StringContent某个重载构造函数可直接传参,设置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强化了区别,在实际开发中要灵活使用。

我又踩坑了!如何为HttpClient请求设置Content-Type?的更多相关文章

  1. Flask框架踩坑之ajax跨域请求

    业务场景: 前后端分离需要对接数据接口. 接口测试是在postman做的,今天才开始和前端对接,由于这是我第一次做后端接口开发(第一次嘛,问题比较多)所以在此记录分享我的踩坑之旅,以便能更好的理解,应 ...

  2. Selenium爬虫实践(踩坑记录)之ajax请求抓包、浏览器退出

    上一篇: 使用Selenium截取网页上的图片 前言 最近在搞公司内部系统,累的一批,需要从另一个内部系统导出数据存到数据库做分析,有大量的数据采集工作,又没办法去直接拿到那个系统的接口,太难了,只能 ...

  3. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  4. HttpWebRequest 改为 HttpClient 踩坑记-请求头设置

    HttpWebRequest 改为 HttpClient 踩坑记-请求头设置 Intro 这两天改了一个项目,原来的项目是.net framework 项目,里面处理 HTTP 请求使用的是 WebR ...

  5. WebForm路由踩坑 ajax请求多次

    WebForm路由踩坑 再次接触Asp.Net WebForm已是4年后的今天,源起新入职的公司,一个老的项目. Web接触的少,那就多动手写写. WebForm1.aspx <body> ...

  6. HttpClient在多线程环境下踩坑总结

    问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状态. 而且,从程序日志中判断有线程处于han ...

  7. 微信小程序 请求签名接口超时 踩坑路。。

    我们公司一般做开发都是先用测试机的接口调试功能,等功能都调试的差不多了,再换成线上的正式接口,因为正式接口要验证签名. 这几个功能都调试的差不多了,准备换成线上正式接口了,结果却出了问题,提示请求超时 ...

  8. 【踩坑记】从HybridApp到ReactNative

    前言 随着移动互联网的兴起,Webapp开始大行其道.大概在15年下半年的时候我接触到了HybridApp.因为当时还没毕业嘛,所以并不清楚自己未来的方向,所以就投入了HybridApp的怀抱. Hy ...

  9. html2canvas以及domtoimage的使用踩坑总结

    前言 首先做个自我介绍,我是成都某企业的一名刚刚入行约一年的前端,在之前的开发过程中,遇到了问题,也解决了问题,但是在下一次解决相同问题的时候,只对这个问题有一丝丝的印象,还需要从新去查找,于是,我注 ...

  10. 我的微信小程序入门踩坑之旅

    前言 更好的阅读体验请:我的微信小程序入门踩坑之旅 小程序出来也有一段日子了,刚出来时也留意了一下.不过赶上生病,加上公司里也有别的事,主要是自己犯懒,就一直没做.这星期一,赶紧趁着这股热乎劲,也不是 ...

随机推荐

  1. [转帖]聊聊TPS、QPS、CPS概念和区别

    https://cloud.tencent.com/developer/article/1859053 TPS 概念 TPS:是TransactionsPerSecond的缩写,也就是事务数/秒.它是 ...

  2. [转帖]存储器分级:L1 Cache 比内存和 SSD 快多少倍?

    目录 1.为什么会有存储器分级策略? 2.存储器分级策略 2.1 存储器的级别 2.2.1 L1-Cache 2.2.2 L2-Cache 2.2.3 L3-Cache 3.内存 4.SSD 和硬盘 ...

  3. [转帖]Linux 内核的 4 大 IO 调度算法

    https://cloud.tencent.com/developer/article/1615744 Linux 内核包含4个IO调度器,分别是 Noop IO scheduler.Anticipa ...

  4. [转帖]查看mysql分区名和各分区数据量

    – 查看mysql分区名和各分区数据量 SELECT table_name, partition_name, table_rows FROM information_schema.PARTITIONS ...

  5. [转帖]dd 自动压测与结果解析脚本

    测试串行.并发.读.写 4类操作,每类操作又可以指定各种bs及count值,循环压测.每种场景一般执行3次,取平均值. 一. 串行写 #!/bin/sh bs_list=(256k 1024k 10M ...

  6. [转帖]jmap执行失败了,怎么获取heapdump?

    https://www.jianshu.com/p/f4bfd169b4ca   在之前的OOM问题复盘中,我们添加了jmap脚本来自动dump内存现场,方便排查OOM问题. 但当我反复模拟OOM场景 ...

  7. 自己想的一些判断存储长度的sql

    create table zhaobsh (t1 date ,t2 TIMESTAMP) insert into zhaobsh values (CURRENT_DATE,CURRENT_TIMEST ...

  8. 【三】多智能体强化学习(MARL)近年研究概览 {Analysis of emergent behaviors(行为分析)_、Learning communication(通信学习)}

    相关文章: [一]最新多智能体强化学习方法[总结] [二]最新多智能体强化学习文章如何查阅{顶会:AAAI. ICML } [三]多智能体强化学习(MARL)近年研究概览 {Analysis of e ...

  9. tensorflow语法【shape、tf.trainable_variables()、Optimizer.minimize()】

    相关文章: [一]tensorflow安装.常用python镜像源.tensorflow 深度学习强化学习教学 [二]tensorflow调试报错.tensorflow 深度学习强化学习教学 [三]t ...

  10. x64dbg 实现插件Socket反向通信

    编写一个带有socket通信功能的插件,x64dbg运行后,用户点击链接按钮可直接连接到外部的python中,python作为服务端,当x64dbg内部出现某个事件后,自动将消息推送到外部python ...