我又踩坑了!如何为HttpClient请求设置Content-Type标头?
最近在重构认证代码,认证过程相当常规:
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.干货旁白
小编对于Http协议有知识漏洞,搬砖时一直关注Chrome DevTools,忽略了还有Entity Header一说。
Content-Type 这个实体标头,会出现了请求/响应标头,指示资源的媒体类型。
.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标头?相关推荐
- 我又踩坑了!如何为 HttpClient 请求设置 Content-Type 标头?
作者 | 小码甲 来源 | Dotnet Plus(ID:nodotnet) 头图 | CSDN 下载自东方IC 最近在重构认证代码,认证过程相当常规: POST /open-api/v1/user ...
- 踩坑 :vue2 ajax异步请求数据,层数太多,页面无法渲染
刚接触vue2不是太久,勉强算是小白一枚吧,在此分享一下我最近踩的一个坑,望以后的小白们借鉴: 首先,数据结构: data(){ return { outer: { mid: [{ inner: &q ...
- python flask跨域_Flask框架踩坑之ajax跨域请求实现
Python flask ajax 请夜影驱动编程小编今天和大家分享后端并且能获得数据,但是...@app.route('/search',methods=[ 'POST']) def search( ...
- 【踩坑专栏】NoSuchBeanDefinitionException: No qualifying bean of type ‘xxx.xxxMapper
在启动的时候遇到了报错,如题. 解决办法就是在启动类上加上mapper的路径扫描, @MapperScan("my.repo.infrastructure.mapper") 其实这 ...
- 【仙女踩坑实录】Ubuntu20.04系统设置打开后闪退
时隔数月,我又踩坑了. 今天打开设置想...我已经忘了当时想干啥了,反正是想打开设置,然后突然发现,设置打不开了,或者说打开后界面都看不到就闪退了. 于是我看到有人在评论区中说是因为显示在扩展屏幕,从 ...
- HttpClient在多线程环境下踩坑总结
HttpClient在多线程环境下踩坑总结 问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状 ...
- Ajax请求SSM后台传值方式踩坑
场景 在Ajax请求接口返回结果后,再次请求后台Controller.原来代码 $("#book").submit(function() {if($(this).Andrew_Va ...
- uc浏览器请求被拦截报跨域踩坑记录
记录下开发时uc浏览器请求被拦截时遇到的问题 请求在uc浏览器出现跨域问题 app使用uniapp开发,使用plus.runtime.launchApplication来打开并跳转指定页面,并在Xco ...
- restTemplate使用和踩坑总结
日常工作中肯定会遇到服务之间的调用,尤其是现在都是微服务的架构,所以总结一下restTemplate的最常用的用法以及自己踩过的坑. restTemplate的使用 restTemplate底层调用的 ...
最新文章
- 2018谷歌学术指数发布——看看综合、生物、生信、微生物领域高引文章和杂志
- 超级列表框排序mysql_超级列表框List Ctrl
- outlook从服务器中恢复已删除项目,Exchange 恢复已删除项目
- 移动端布局三种视口_移动端开发知识[系列] - 视口viewport
- 高德最佳实践:Serverless规模化落地有哪些价值?
- window版docker安装及配置
- python配置文件密码管理_用户配置文件和密码配置文件,用户组管理和用户管理...
- 剑指 Offer 32-I/32-II/32-III从上到下打印二叉树c++
- indesign用于产品排班_InDesign排版:设计师的基本印刷知识
- meta pseudo label
- 关于微信开发者没有上传按钮的问题
- mac 版VirtualBox 安装win10方法 全屏
- SpringBoot 集成 WebSocket 实现消息群发推送
- 云服务器更新系统,云服务器能更新系统吗
- python中可以清空字典并保留变量的是,给定字典d,以下选项中可以清空该字典并保留变量的...
- 8个超好用的免费工具/软件/网站(一定有你要的)
- python归一化和反归一化_python:什么是归一化以及怎么做归一化?
- [Python Scrapy爬虫] 二.翻页爬取农产品信息并保存本地
- 【C语言】自定义函数例题解析
- 机器学习实践:超市商品购买关联规则分析
热门文章
- 解决Maven管理项目update Maven时,jre自动变为1.5
- visual studio开启多核编译方法
- 使用java开发简单的mis系统所需的技术
- Java从零开始(二) Tomacat
- arcgis server 无法手动删除切片
- roku能不能安装软件_如何在Roku中使用Google Assistant
- 如何在Windows 10的地图应用程序中获取离线地图
- 计算机二级高级应用这么难,计算机二级考试越来越难的实锤!真实数据告诉你到底难在哪里?...
- Pressed状态和clickable,duplicateParentState的关系
- Lintcode165 Merge Two Sorted Lists solution 题解