在 HttpResponseMessage / HttpRequestMessage(System.Net.Http, WebAPI)中查看将要发送/接收的原始标头。

8
在WebAPI的HttpResponseMessage / HttpRequestMessage类型中,直接看到实际发送或接收的Http Headers原始列表可能非常有益。我的意思是一个普通的字符串,每个报头都在新行上,完全是生成或接收的内容。
但不幸的是,这两种类型似乎都不能让你看到实际生成的内容。相反,属性随处可见。有些在原始的HttpResponseMessage / HttpRequestMessage类型本身中,有些在response/request.Content.Headers中(两者不重复,后者用于通常用于自定义标头的未覆盖为属性的标头),...也许Cookie还有自己的标头集合。而且可视化地查看这些Header集合也很麻烦,即你最终会得到一堆迭代代码来处理每个这样的集合...更加混乱。
但在实际发送/接收的响应/请求中,没有这样的区分,可以轻松地查看所有的Http headers。那么我是否错过了什么?这些类型中是否实际上有一个简单直观的属性,只返回原始的headers字符串?毫无疑问,响应已经接收到了header并解析了它们...这个原始字符串藏在哪里呢?
(顺便说一句,我知道Fiddler...但那完全是不令人满意的。如果我必须处理Http headers的低级问题,那么使用生成和接收它们的编程类型来查看它们是很有意义的。但更糟糕的是,我仍然不能让localhost与Fiddler(在Win8上)一起工作,这使得它对许多调试场景无法使用,其中我想做的就是看到将要生成的头文件。)

我有同样的问题。似乎没有 HttpRequestMessage.Raw 属性或类似的东西。我想我必须重新创建原始响应,给定 HeadersContent 属性。 - NathanAldenSr
1
你在这方面有什么进展吗?我已经成功地使用在GlobalConfiguration中注册的自定义消息处理程序获得了原始请求和响应的相似性,但是在响应中,标头只包含由Web API设置的标头,而IIS添加的标头则不存在。我希望他们能够在某个地方提供原始请求和响应属性,而不是将其隐藏在抽象层中! - user692942
"我只希望他们能够提供一个原始请求和响应属性,而不是把它隐藏在抽象层之中!" - 太对了! - Nicholas Petersen
3个回答

4

我没有找到获取原始请求头值的方法,但是这段代码似乎返回所有头部值(不按原始顺序):

request.Headers.ToString() + request.Content.Headers.ToString()

0

看起来HttpRequestMessage.ToString返回原始值(严格来说它们不是原始值,但非常接近原始值,因为它使用解析器分隔符将它们拼接回来)。不幸的是,用于构造ToString结果的方法是私有的。因此,为了解决相同的任务,我不得不解析ToString的结果:

var values = new JObject();

foreach (var raw_header in request.Headers
                                   .ToString()
                                   .Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
{
    var index = raw_header.IndexOf(':');
    if (index <= 0)
        continue;

    var key = raw_header.Substring(0, index);
    var value = index + 1 >= raw_header.Length ? string.Empty : raw_header.Substring(index + 1).TrimStart(' ');

    values.Add(new JProperty(key, value));
}

-1
这是我用来捕获请求和响应头的代码:
*这是从Windows Forms应用程序中获取的,所以:txtReceived和txtSent是WindowsForms表单上简单的多行文本框。光标是表单的光标。*
    private HttpClient PrepareHttpClient()
    {
        var client = new HttpClient();

        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/xml"));

        return client;
    }

    private string SendGetRequest(string url)
    {
        //Please be patient ...
        this.Cursor = Cursors.WaitCursor;

        var client = PrepareHttpClient();
        txtSent.Text = url;
        var taskReult = client.GetAsync(new Uri(url));
        HttpResponseMessage httpResponse = taskReult.Result;

        Stream st = httpResponse.Content.ReadAsStreamAsync().Result;
        StreamReader reader = new StreamReader(st);
        string content = reader.ReadToEnd();

        //Reset the cursor shape
        this.Cursor = Cursors.Default;

        txtReceived.Text = FormatResponse(httpResponse, content);

        //For GET we expect a response of 200 OK
        if (httpResponse.StatusCode == HttpStatusCode.OK)
        {
            return content;
        }

        throw new ApplicationException(content);
    }
    /// <summary>
    /// Post to the server using JSON
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url">The server uri</param>
    /// <param name="e">The object to POST</param>
    /// <returns></returns>
    private string SendPostRequest<T>(string url, T e)
    {
        this.Cursor = Cursors.WaitCursor;
        HttpClient client = new HttpClient();

        // Create the JSON formatter.
        MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();

        // Use the JSON formatter to create the content of the request body.
        HttpContent content = new ObjectContent<T>(e, jsonFormatter);
        Stream st = content.ReadAsStreamAsync().Result;
        StreamReader reader = new StreamReader(st);
        string s = reader.ReadToEnd();


        // Send the request.
        var taskResult = client.PostAsync(url, content);

        //Note: We could simply perform the following line and save some time
        //but then we will not have access to the post content:
        //var taskResult = client.PostAsJsonAsync<T>(url, e);

        HttpResponseMessage httpResponse = taskResult.Result;
        this.Cursor = Cursors.Default;

        txtSent.Text = FormatRequest(httpResponse.RequestMessage, s);

        st = httpResponse.Content.ReadAsStreamAsync().Result;
        reader = new StreamReader(st);
        string responseContent = reader.ReadToEnd();
        txtReceived.Text = FormatResponse(httpResponse, responseContent);

        //For POST we expect a response of 201 Created
        if (httpResponse.StatusCode == HttpStatusCode.Created)
        {
            return responseContent;
        }

        throw new ApplicationException(responseContent);
    }

    /// <summary>
    /// PUT to the server using JSON
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private string SendPutRequest<T>(string url, T e)
    {
        this.Cursor = Cursors.WaitCursor;
        HttpClient client = new HttpClient();

        // Create the JSON formatter.
        MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();

        // Use the JSON formatter to create the content of the request body.
        HttpContent content = new ObjectContent<T>(e, jsonFormatter);
        Stream st = content.ReadAsStreamAsync().Result;
        StreamReader reader = new StreamReader(st);
        string s = reader.ReadToEnd();

        // Send the request.
        var taskResult = client.PutAsync(url, content);

        //Note: We could simply perform the following line and save some time
        //but then we will not have access to the post content:
        //var taskResult = client.PutAsJsonAsync<T>(url, e);

        HttpResponseMessage httpResponse = taskResult.Result;

        txtSent.Text = FormatRequest(httpResponse.RequestMessage, s);

        st = httpResponse.Content.ReadAsStreamAsync().Result;
        reader = new StreamReader(st);
        string responseContent = reader.ReadToEnd();
        this.Cursor = Cursors.Default;
        txtReceived.Text = FormatResponse(httpResponse, responseContent);

        //For PUT we expect a response of 200 OK
        if (httpResponse.StatusCode == HttpStatusCode.OK)
        {
            return responseContent;
        }

        throw new ApplicationException(responseContent);
    }

    private string FormatRequest(HttpRequestMessage request, string content)
    {
        return
            string.Format("{0} {1} HTTP/{2}\r\n{3}\r\n{4}",
                request.Method,
                request.RequestUri,
                request.Version,
                request.Headers,
                content);
    }

    private string FormatResponse(HttpResponseMessage result, string content)
    {
        return
            string.Format("HTTP/{0} {1} {2}\r\n{3}\r\n{4}",
                result.Version,
                (int)result.StatusCode,
                result.ReasonPhrase,
                result.Headers,
                content);
    }

谢谢Dror,但是很抱歉,大部分代码都不需要发帖,因为它们与问题完全无关。我也没能找出其中一个实际答案,给出响应字符串的相似物。 - Nicholas Petersen
2
我目前使用的是一种 重建 响应字符串的方法,试图使其尽可能看起来像您期望找到的原始响应。我可能会最终发布那个解决方案,其中包含许多检查每个可能的标题变量的冗长方法。这完全是荒谬的。一个简单的基于文本的字符串进来了,我呼吁团队请给我们一种获取纯字符串的方法。这有助于我们所有开发人员的工作,只需看到它即可。 - Nicholas Petersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接