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

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

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


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"}


a0767877c181c6598cd1ffe9a3bda1bf.png


平台显示 :签名校验失败, 排查到平台收到的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 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啊?


46173861309e4a89a9c798ce1aa1d1c5.png


2.  爬坑


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


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


Content-Type属于Entity Header的一种,对应.NET类型  HttpContentHeader;


虽然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一说。


  1. Content-Type 这个实体标头(实体标头通常会出现在请求/响应标头中),指示资源的媒体类型。


  1. .NTE针对4种HTTP Header强化了区别,在实际开发中要区别使用。
相关文章
|
1月前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
2月前
|
JSON 中间件 数据格式
django获取request请求头信息,获取Content-Type
django获取request请求头信息,获取Content-Type
49 4
|
6月前
|
JSON PHP 数据格式
蓝易云 - PHP用CURL发送Content-type为application/json的POST请求方法
在这段代码中,我们首先创建了一个包含我们要发送的数据的数组,并使用 `json_encode`函数将其转换为JSON格式。然后,我们初始化了一个cURL会话,并设置了一些选项,包括POST请求方法、要发送的数据、返回结果和HTTP头部信息。最后,我们执行了cURL请求并关闭了会话。
169 2
|
7月前
|
XML JSON Java
Android App网络通信中通过okhttp调用HTTP接口讲解及实战(包括GET、表单格式POST、JSON格式POST 附源码)
Android App网络通信中通过okhttp调用HTTP接口讲解及实战(包括GET、表单格式POST、JSON格式POST 附源码)
1062 0
|
7月前
|
API
webclient在delete请求时携带request body
webclient在delete请求时携带request body
127 0
|
前端开发 Java
java在过滤器中为http请求加请求头header
现在有一个需求场景是,每一个请求我都需要在请求头里面加上token这个请求头,作为一种校验机制,传统的接口可以通过设置一个全局的变量,然后通过页面携带过来(大概就是先将我们的token放在session中,写一个服务用来获取session中的token,然后主页面用ajax调用接口,将token放在隐藏域中,然后将请求头放进来,用ajax方法,这里不想洗说了),但是有一种情况是通过页面传递的并不一定都会适用所有接口,比如上传和下载的接口有时候头里面就没有token参数,可能是上传和下载是用表单提交的 这个时候如何将请求头通过后台的方法加进来? 想到用过滤器,用后台方法强制加入请求头。
165 0
|
Web App开发
JavaWeb - HTTP 请求中 Post 和 Put 区别
JavaWeb - HTTP 请求中 Post 和 Put 区别
252 0
|
XML JSON 开发工具
浅析http请求的content-type及使用场景
在HTTP协议消息头中,使用Content-Type来表示媒体类型信息。它被用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析html或仅仅展示一个文本等。
362 0
|
存储 SQL JSON
HTTP协议中的“报头”(header)和 “正文“ (body)详解
HTTP协议中的“报头”(header)和 “正文“ (body)详解
HTTP协议中的“报头”(header)和 “正文“ (body)详解
Java进行http请求时,放置会话信息到header里面
Java进行http请求时,放置会话信息到header里面
269 0