【问题标题】:How to clone a HttpRequestMessage when the original request has Content?当原始请求有内容时如何克隆 HttpRequestMessage?
【发布时间】:2014-07-30 18:23:24
【问题描述】:

我正在尝试使用此答案中概述的方法克隆请求: https://stackoverflow.com/a/18014515/406322

但是,如果原始请求有内容,我会收到 ObjectDisposedException。

如何可靠地克隆 HttpRequestMessage?

【问题讨论】:

  • 我不知道你能不能。例如,如果您打开一个流并将其用作内容,则该流只能使用一次。原件是在哪里创建的?
  • 我的原始请求是一个PUT,带有一个身份验证头和一些参数作为内容。我需要重试(但每次重试都要更改标题),那么我的选择是什么?

标签: c# .net rest http dotnet-httpclient


【解决方案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&lt;string, object?&gt; option in req.Options) clone.Options.Set(new HttpRequestOptionsKey&lt;object?&gt;(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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-17
    • 2010-09-06
    • 2017-02-21
    • 2013-09-15
    • 2014-04-01
    • 1970-01-01
    相关资源
    最近更新 更多