我又踩坑了!如何为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强化了区别,在实际开发中要区别使用。
目录
打赏
0
0
0
0
11
分享
相关文章
Uniapp~动态修改 请求头的content-type 的值
Uniapp~动态修改 请求头的content-type 的值
1404 0
Uniapp~动态修改 请求头的content-type 的值
Http协议中的Header与Body
Http协议中的Header与Body Header的每行最后要加\r\n Header与Body之间要用\r\n隔开 Body后无需加\r\n ACSII码中 '\n' 10 换行 '\r' 13 回车 也可以表示为'\x0a'和'\x0d'.(16进制) 示例:HTTP开始部分为header,部分为body。
2328 0
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
121 25
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
蓝易云 - PHP用CURL发送Content-type为application/json的POST请求方法
在这段代码中,我们首先创建了一个包含我们要发送的数据的数组,并使用 `json_encode`函数将其转换为JSON格式。然后,我们初始化了一个cURL会话,并设置了一些选项,包括POST请求方法、要发送的数据、返回结果和HTTP头部信息。最后,我们执行了cURL请求并关闭了会话。
219 2
基础入门 HTTP数据包&Postman构造&请求方法&请求头修改&状态码判断
基础入门 HTTP数据包&Postman构造&请求方法&请求头修改&状态码判断
【JavaEE初阶】 HTTP 请求 (Request)详解
【JavaEE初阶】 HTTP 请求 (Request)详解
HTTP Content-Type 类型解析
【1月更文挑战第10天】HTTP Content-Type 类型解析
JavaWeb - HTTP 请求中 Post 和 Put 区别
JavaWeb - HTTP 请求中 Post 和 Put 区别
277 0
java在过滤器中为http请求加请求头header
现在有一个需求场景是,每一个请求我都需要在请求头里面加上token这个请求头,作为一种校验机制,传统的接口可以通过设置一个全局的变量,然后通过页面携带过来(大概就是先将我们的token放在session中,写一个服务用来获取session中的token,然后主页面用ajax调用接口,将token放在隐藏域中,然后将请求头放进来,用ajax方法,这里不想洗说了),但是有一种情况是通过页面传递的并不一定都会适用所有接口,比如上传和下载的接口有时候头里面就没有token参数,可能是上传和下载是用表单提交的 这个时候如何将请求头通过后台的方法加进来? 想到用过滤器,用后台方法强制加入请求头。
193 0
HTTP的PUT请求和POST请求的区别是什么?底层原理是什么?
HTTP的PUT请求和POST请求的区别是什么?底层原理是什么?
503 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等