作者 | 小码甲

来源 | 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 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 啊?

爬坑

官方资料显示: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?看完这个故事就明白了!
☞区块链+生鲜:杜绝“偷梁换柱”和“以次充好”
点分享点点赞点在看

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

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

    最近在重构认证代码,认证过程相当常规: POST /open-api/v1/user-info?client_id&timstamp&rd=12345&sign=***& ...

  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. Python:Scrapy的安装和入门案例
  2. Worksheet.get_Range Method
  3. css 链接悬浮动画
  4. 同步阻塞、同步非阻塞、异步阻塞、异步非阻塞与 I/O 多路复用、Java NIO 之间的联系
  5. 【windows】windows允许 ICMP协议(允许ping)
  6. 一个超级简单的csv读取工具类
  7. 手动配置S2SH三大框架报错(三)
  8. Vue面试中,经常会被问到的面试题
  9. LeetCode-----第113题-----路径总和 II
  10. Allegro-PCB导入DXF文件
  11. VS Code PHP代码提示和格式化插件 IntelliSense安装使用
  12. 计算机毕业设计Node.js+Vue交通违章举报平台(程序+源码+LW+部署)
  13. Redis启动窗口一闪就关
  14. 单片机产生可调方波(c语言),为什么我用单片机做的频率可调的方波输出会有尖刺,而且会断...
  15. linux下使用ffmpeg将amr转成mp3(转)
  16. mac连接服务器打不开网页,Mac电脑联接网络但是浏览器打不开网页
  17. opencv-python 绘制图像直方图及直方图均衡化
  18. 用asp怎样编写文档搜索页面
  19. IOS微信6.7.4输入框失去焦点,软键盘关闭后,被撑起的页面无法回退到原来正常的位置
  20. python到pandas_Python-Pandas

热门文章

  1. 【计算机网络】TCP关闭连接问题及注意
  2. 第四次博客:循环单链表解决约瑟夫环问题
  3. 20190313_C#反转绘制字符串
  4. 给网站插入一个百度地图API
  5. mysqlbackup 重建带有gtid特性的slave
  6. Java 容器类练习题(一)
  7. Servlet工作原理解析2(以Tomcat为例)
  8. LeetCode 234 Palindrome Linked List
  9. 质因数分解(0)P2012_1
  10. opencv-阈值处理