該篇主要説明使用 Windows.Web.Http.HttpClient 遇到裏面的 Header 需要 Redirect 出現 A redirect request will change a secure to a non-secure connection
的解決方式。
情況是這樣的:
1. 今天在使用 HttpClient 打 API 的時候,遇到 SendRequestAsync 之後就會拿到如下圖的結果: 可以看到幾個關鍵的訊息:
- Exception thrown: 'System.AggregateException' in mscorlib.ni.dll
-
The text associated with this error code could not be found.
A redirect request will change a secure to a non-secure connection
。
説明原本的 request 被 redirect 到另一個不安全的 URL 的地方(例如 https 導向 http)。
HttpClient 預設是會自動 redirect
的:
private void HttpClient GetHttpClient()
{
var httpFilter = new HttpBaseProtocolFilter();
httpFilter.CacheControl.ReadBehavior = HttpCacheReadBehavior.MostRecent;
httpFilter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache;
// 關掉自動 redirect 的功能
httpFilter.AllowAutoRedirect = false;
return new HttpClient(httpFilter);
}
這個時候就可以發現 redirect 被放在 response 的 Header 里説明 Status Code 跟 redirect URL,如下圖:
發現它被倒入另一個 https 的 URL,這個跟 A redirect request will change a secure to a non-secure connection
好像沒有任何關係。
問題來了 Status Code = 302 (Found),明確的告訴 HttpClient 需要導向,但是目的 URL 是 HttpClient 不認識的 URL,所以就會一直出現錯誤。
也許你會問,把要去的那個 URL 加入到 package.appxmanifest 的安全名單 <uap:ApplicationContentUriRules /> 可以嗎?答案: 一樣沒有辦法解決。
3. 自行爲 HttpClient 開發遇到 Status Code = 320 的 redirect 任務:
public HttpCompletionOption CompletionOption { get; set; } = HttpCompletionOption.ResponseContentRead;
private void InvokeAPI()
{
// 取得 HttpClient
using (HttpClient client = GetHttpClient())
{
HttpRequestMessage request = new HttpRequestMessage();
redirectMsg.RequestUri = new Uri("{Your API URL}");
// 利用遞回的方式完成 redirect
var result = LoopRedirect(client, httpRequestMessage, timeout).Result;
}
}
private async Task<HttpResponseMessage> LoopRedirect(HttpClient client, HttpRequestMessage httpRequestMessage, int timeout)
{
var cancellationToken = (cancellationTokenSource == null ? CancellationToken.None : cancellationTokenSource.Token);
var sendTask = client.SendRequestAsync(httpRequestMessage, CompletionOption).AsTask(cancellationToken);
var response = sendTask.Result;
if (response.StatusCode == Windows.Web.Http.HttpStatusCode.Found)
{
var redirectMsg = new HttpRequestMessage();
redirectMsg.RequestUri = new Uri(response.Headers.Location.AbsoluteUri);
return await LoopRedirect(client, redirectMsg, timeout);
}
else
{
return response;
}
}
利用遞回的方式來完成 redirect 就可以解決 HttpClient 在自動 redirect 遇到的問題。
======
這個問題我在 8.1 (UAP) 的開發上是正常的,我不確定是不是新的 UWP 又做了什麽調整。
但是可以確定的是如果遇到 HttpClient 需要被 redirect 失敗時,還是手動自己做會比較安全。
建議把 http 都變成 https 吧!!
References:
- Getting exception in System.Net.HttpClient - A redirect request will change a secure to a non-secure connection
- Demystifying HttpClient APIs in the Universal Windows Platform
- Windows 8.1 Windows.Web.HTTP.HTTPClient - Secure to Non Secure Redirect Exception
- Windows 8.1 Windows.Web.HTTP.HTTPClient - Secure to Non Secure Redirect Exception