当原始请求有内容时如何克隆 HttpRequestMessage?
Posted
技术标签:
【中文标题】当原始请求有内容时如何克隆 HttpRequestMessage?【英文标题】:How to clone a HttpRequestMessage when the original request has Content? 【发布时间】:2014-07-30 18:23:24 【问题描述】:我正在尝试使用此答案中概述的方法克隆请求: https://***.com/a/18014515/406322
但是,如果原始请求有内容,我会收到 ObjectDisposedException。
如何可靠地克隆 HttpRequestMessage?
【问题讨论】:
我不知道你能不能。例如,如果您打开一个流并将其用作内容,则该流只能使用一次。原件是在哪里创建的? 我的原始请求是一个PUT,带有一个身份验证头和一些参数作为内容。我需要重试(但每次重试都要更改标题),那么我的选择是什么? 【参考方案1】:这应该可以解决问题:
public static async Task<HttpRequestMessage> CloneHttpRequestMessageAsync(HttpRequestMessage req)
HttpRequestMessage clone = new HttpRequestMessage(req.Method, req.RequestUri);
// Copy the request's content (via a MemoryStream) into the cloned object
var ms = new MemoryStream();
if (req.Content != null)
await req.Content.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
clone.Content = new StreamContent(ms);
// Copy the content headers
if (req.Content.Headers != null)
foreach (var h in req.Content.Headers)
clone.Content.Headers.Add(h.Key, h.Value);
clone.Version = req.Version;
foreach (KeyValuePair<string, object> prop in req.Properties)
clone.Properties.Add(prop);
foreach (KeyValuePair<string, IEnumerable<string>> header in req.Headers)
clone.Headers.TryAddWithoutValidation(header.Key, header.Value);
return clone;
【讨论】:
我刚刚使用了这个 sn-p,到目前为止它工作正常。 @Prahbu:你能把它标记为正确答案吗? 使用“using”关键字避免内存泄漏:using var ms = new MemoryStream(); 从 .net 5 开始,req.Content.Headers
永远不会是 null
,因此检查是否为空是没有意义的。我只是在没有条件的情况下运行循环。 req.Properties
也已过时,应使用 req.Options
代替。
所以在 .NET 5 中,它应该更改为 foreach (KeyValuePair<string, object?> option in req.Options) clone.Options.Set(new HttpRequestOptionsKey<object?>(option.Key), option.Value);
为什么不只是clone.Content = req.Content
?【参考方案2】:
如果对内容调用 LoadIntoBufferAsync,可以保证内容缓冲在 HttpContent 对象内部。剩下的唯一问题就是读取流并不会重置位置,所以需要ReadAsStreamAsync,并设置流Position = 0。
我的示例与 Carlos 展示的示例非常相似...
private async Task<HttpResponseMessage> CloneResponseAsync(HttpResponseMessage response)
var newResponse = new HttpResponseMessage(response.StatusCode);
var ms = new MemoryStream();
foreach (var v in response.Headers) newResponse.Headers.TryAddWithoutValidation(v.Key, v.Value);
if (response.Content != null)
await response.Content.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
newResponse.Content = new StreamContent(ms);
foreach (var v in response.Content.Headers) newResponse.Content.Headers.TryAddWithoutValidation(v.Key, v.Value);
return newResponse;
```
【讨论】:
链接已失效,或许您可以将相关的 sn-p 添加到您的答案中? 文件似乎已被移动,并且 LoadIntoBufferAsync 已被较新的提交删除:github.com/tavis-software/Tavis.HttpCache/commit/… 请注意:此答案与 HttpResponseMessage 克隆有关。问题是关于克隆请求,而不是响应。方法非常相似。【参考方案3】:Carlos 的一些 linq 快捷方式的回答:
public static async Task<HttpRequestMessage> Clone(this HttpRequestMessage httpRequestMessage)
HttpRequestMessage httpRequestMessageClone = new HttpRequestMessage(httpRequestMessage.Method, httpRequestMessage.RequestUri);
if (httpRequestMessage.Content != null)
var ms = new MemoryStream();
await httpRequestMessage.Content.CopyToAsync(ms);
ms.Position = 0;
httpRequestMessageClone.Content = new StreamContent(ms);
httpRequestMessage.Content.Headers?.ToList().ForEach(header => httpRequestMessageClone.Content.Headers.Add(header.Key, header.Value));
httpRequestMessageClone.Version = httpRequestMessage.Version;
httpRequestMessage.Properties.ToList().ForEach(props => httpRequestMessageClone.Properties.Add(props));
httpRequestMessage.Headers.ToList().ForEach(header => httpRequestMessageClone.Headers.TryAddWithoutValidation(header.Key, header.Value));
return httpRequestMessageClone;
【讨论】:
以上是关于当原始请求有内容时如何克隆 HttpRequestMessage?的主要内容,如果未能解决你的问题,请参考以下文章
从 Microsoft.AspNetCore.Http.HttpRequest 获取原始 URL
尝试在http拦截器中捕获401,刷新我的会话并重试原始请求
如何使用 open office uno API 克隆 TextTable 并将 N 个克隆的 TextTable 粘贴到原始 TextTable 下方