我又踩坑了!如何为HttpClient请求设置Content-Type标头?
最近在重構認證代碼,認證過程相當常規:
平臺顯示?:簽名校驗失敗, 排查到平臺收到的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被分為如下四類:
| 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标头?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Magicodes.IE之花式导出
- 下一篇: 2020 中国开源年会(COSCon'2