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 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 啊?
爬坑官方資料顯示:HTTP Headers 被分為如下四類:
---信息舉例
.NET類型General Header可同時作用在請求/響應中,但是與傳輸數據無關Upgrade、Connection---Request Header將要獲取的資源或客戶端本身的信息Accept、
AuthorizationHttpRequestHeadersResponse Header響應信息Location、ETagHttpResponseHeadersEntity
Header實體Body額外的信息Content-Length、
ConnectionHttpContentHeadersContent-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") );
乾貨旁白小編對於 Http 協議有知識漏洞,搬磚時一直關注 Chrome DevTools,忽略了還有 Entity Header 一說。
Content-Type 這個實體標頭,會出現了請求/響應標頭,指示資源的媒體類型。
.NTE 針對4種 HTTP Header 強化了區別,在實際開發中要區別使用。
更多精彩推薦
☞300億美元,AMD為什麼要買Xilinx?
☞1024程式設計師節開源技術英雄會,參會「英雄榜」發榜
☞如何應對雲原生之旅中的安全挑戰?
☞採摘工人月薪十萬卻無人應聘,英澳農場求助 AI
☞還不懂Redis?看完這個故事就明白了!
☞區塊鏈+生鮮:杜絕「偷梁換柱」和「以次充好」