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

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

1. 入坑

下面是构造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 headerc.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啊?

2.  爬坑

官方资料显示: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。

3. 填坑

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

4.干货旁白

  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

- -

  • ASP.NET Core端点路由作用原理

  • 临近年关,修复ASP.NET Core因浏览器内核版本引发的单点登录故障

  • ASP.NET Core 基于声明的访问控制到底是什么鬼?

  • 大揭秘| 我司项目组Gitlab Flow && DevOps流程

  • 为什么我们需要Logstash,Fluentd等日志摄取器?

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

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

    作者 | 小码甲 来源 | Dotnet Plus(ID:nodotnet) 头图 |  CSDN 下载自东方IC 最近在重构认证代码,认证过程相当常规: POST /open-api/v1/user ...

  2. 踩坑 :vue2 ajax异步请求数据,层数太多,页面无法渲染

    刚接触vue2不是太久,勉强算是小白一枚吧,在此分享一下我最近踩的一个坑,望以后的小白们借鉴: 首先,数据结构: data(){ return { outer: { mid: [{ inner: &q ...

  3. python flask跨域_Flask框架踩坑之ajax跨域请求实现

    Python flask ajax 请夜影驱动编程小编今天和大家分享后端并且能获得数据,但是...@app.route('/search',methods=[ 'POST']) def search( ...

  4. 【踩坑专栏】NoSuchBeanDefinitionException: No qualifying bean of type ‘xxx.xxxMapper

    在启动的时候遇到了报错,如题. 解决办法就是在启动类上加上mapper的路径扫描, @MapperScan("my.repo.infrastructure.mapper") 其实这 ...

  5. 【仙女踩坑实录】Ubuntu20.04系统设置打开后闪退

    时隔数月,我又踩坑了. 今天打开设置想...我已经忘了当时想干啥了,反正是想打开设置,然后突然发现,设置打不开了,或者说打开后界面都看不到就闪退了. 于是我看到有人在评论区中说是因为显示在扩展屏幕,从 ...

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

    HttpClient在多线程环境下踩坑总结 问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状 ...

  7. Ajax请求SSM后台传值方式踩坑

    场景 在Ajax请求接口返回结果后,再次请求后台Controller.原来代码 $("#book").submit(function() {if($(this).Andrew_Va ...

  8. uc浏览器请求被拦截报跨域踩坑记录

    记录下开发时uc浏览器请求被拦截时遇到的问题 请求在uc浏览器出现跨域问题 app使用uniapp开发,使用plus.runtime.launchApplication来打开并跳转指定页面,并在Xco ...

  9. restTemplate使用和踩坑总结

    日常工作中肯定会遇到服务之间的调用,尤其是现在都是微服务的架构,所以总结一下restTemplate的最常用的用法以及自己踩过的坑. restTemplate的使用 restTemplate底层调用的 ...

最新文章

  1. 2018谷歌学术指数发布——看看综合、生物、生信、微生物领域高引文章和杂志
  2. 超级列表框排序mysql_超级列表框List Ctrl
  3. outlook从服务器中恢复已删除项目,Exchange 恢复已删除项目
  4. 移动端布局三种视口_移动端开发知识[系列] - 视口viewport
  5. 高德最佳实践:Serverless规模化落地有哪些价值?
  6. window版docker安装及配置
  7. python配置文件密码管理_用户配置文件和密码配置文件,用户组管理和用户管理...
  8. 剑指 Offer 32-I/32-II/32-III从上到下打印二叉树c++
  9. indesign用于产品排班_InDesign排版:设计师的基本印刷知识
  10. meta pseudo label
  11. 关于微信开发者没有上传按钮的问题
  12. mac 版VirtualBox 安装win10方法 全屏
  13. SpringBoot 集成 WebSocket 实现消息群发推送
  14. 云服务器更新系统,云服务器能更新系统吗
  15. python中可以清空字典并保留变量的是,给定字典d,以下选项中可以清空该字典并保留变量的...
  16. 8个超好用的免费工具/软件/网站(一定有你要的)
  17. python归一化和反归一化_python:什么是归一化以及怎么做归一化?
  18. [Python Scrapy爬虫] 二.翻页爬取农产品信息并保存本地
  19. 【C语言】自定义函数例题解析
  20. 机器学习实践:超市商品购买关联规则分析

热门文章

  1. 解决Maven管理项目update Maven时,jre自动变为1.5
  2. visual studio开启多核编译方法
  3. 使用java开发简单的mis系统所需的技术
  4. Java从零开始(二) Tomacat
  5. arcgis server 无法手动删除切片
  6. roku能不能安装软件_如何在Roku中使用Google Assistant
  7. 如何在Windows 10的地图应用程序中获取离线地图
  8. 计算机二级高级应用这么难,计算机二级考试越来越难的实锤!真实数据告诉你到底难在哪里?...
  9. Pressed状态和clickable,duplicateParentState的关系
  10. Lintcode165 Merge Two Sorted Lists solution 题解