我使用了@DarrelMiller 的解决方案并且它有效。但是,我做了一些改进
我重构了代码,所以现在一切都在CopyRequest
其中response
作为参数。
var newRequest = CopyRequest(response);
base.SendAsync(newRequest, cancellationToken)
.ContinueWith(t2 => tcs.SetResult(t2.Result));
这是我改进后的 CopyRequest 方法
- 而不是创建一个新的
StreamContent
并将其设置为 null,因为Redirect / Found / SeeOther
只有在需要时才设置内容。
- RequestUri 仅在设置 Location 时才设置,并考虑到它可能不是相对 uri。
- 最重要的是:我检查新的 Uri,如果主机不匹配,我不会复制自动化标头,以防止将您的凭据泄露给外部主机。
private static HttpRequestMessage CopyRequest(HttpResponseMessage response)
{
var oldRequest = response.RequestMessage;
var newRequest = new HttpRequestMessage(oldRequest.Method, oldRequest.RequestUri);
if (response.Headers.Location != null)
{
if (response.Headers.Location.IsAbsoluteUri)
{
newRequest.RequestUri = response.Headers.Location;
}
else
{
newRequest.RequestUri = new Uri(newRequest.RequestUri, response.Headers.Location);
}
}
foreach (var header in oldRequest.Headers)
{
if (header.Key.Equals("Authorization", StringComparison.OrdinalIgnoreCase) && !(oldRequest.RequestUri.Host.Equals(newRequest.RequestUri.Host)))
{
//do not leak Authorization Header to other hosts
continue;
}
newRequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
foreach (var property in oldRequest.Properties)
{
newRequest.Properties.Add(property);
}
if (response.StatusCode == HttpStatusCode.Redirect
|| response.StatusCode == HttpStatusCode.Found
|| response.StatusCode == HttpStatusCode.SeeOther)
{
newRequest.Content = null;
newRequest.Method = HttpMethod.Get;
}
else if (oldRequest.Content != null)
{
newRequest.Content = new StreamContent(oldRequest.Content.ReadAsStreamAsync().Result);
}
return newRequest;
}