我正在使用 RestSharp 来调用网络服务。一切都很好,但我想知道是否可以打印发出的原始请求 header 和正文以及返回的原始响应 header 和响应正文。

这是我创建请求并获得响应的代码

public static TResponse ExecutePostCall<TResponse, TRequest>(String url, TRequest requestData, string token= "") where TResponse : new()
{
    RestRequest request = new RestRequest(url, Method.POST);
    if (!string.IsNullOrWhiteSpace(token))
    {
        request.AddHeader("TOKEN", token);
    }


    request.RequestFormat = DataFormat.Json;
    request.AddBody(requestData);

    // print raw request here

    var response = _restClient.Execute<TResponse>(request);

    // print raw response here

    return response.Data;
}

那么,是否可以打印原始请求和响应?

最佳答案

RestSharp 没有提供一种机制来实现您想要的功能,并且激活 .Net 跟踪对 IMO 来说有点矫枉过正。

对于日志记录(调试)目的(例如,我可以在 PROD 中保持开启一段时间)我发现这种方法非常有用(尽管它有一些关于如何调用它的详细信息,请阅读下面的代码):

private void LogRequest(IRestRequest request, IRestResponse response, long durationMs)
{
        var requestToLog = new
        {
            resource = request.Resource,
            // Parameters are custom anonymous objects in order to have the parameter type as a nice string
            // otherwise it will just show the enum value
            parameters = request.Parameters.Select(parameter => new
            {
                name = parameter.Name,
                value = parameter.Value,
                type = parameter.Type.ToString()
            }),
            // ToString() here to have the method as a nice string otherwise it will just show the enum value
            method = request.Method.ToString(),
            // This will generate the actual Uri used in the request
            uri = _restClient.BuildUri(request),
        };

        var responseToLog = new
        {
            statusCode = response.StatusCode,
            content = response.Content,
            headers = response.Headers,
            // The Uri that actually responded (could be different from the requestUri if a redirection occurred)
            responseUri = response.ResponseUri,
            errorMessage = response.ErrorMessage,
        };

        Trace.Write(string.Format("Request completed in {0} ms, Request: {1}, Response: {2}",
                durationMs,
                JsonConvert.SerializeObject(requestToLog),
                JsonConvert.SerializeObject(responseToLog)));
}

注意事项:
  • Headers、Url段、QueryString参数、body等都是RestSharp的参数,都出现在请求的参数集合中,有对应的类型。
  • 必须在请求发生后调用日志方法。由于 RestSharp 的工作方式,Execute 方法将添加 header ,运行身份验证器(如果已配置)等,因此需要这样做,所有这些都会修改请求。因此,为了记录所有发送的真实参数,应该在记录请求之前调用 Execute 方法。
  • RestSharp 本身永远不会抛出(而是将错误保存在 response.ErrorException 属性中),但我认为反序列化可能会抛出(不确定),此外我需要记录原始响应,所以我选择实现我自己的反序列化。
  • 请记住,RestSharp 在转换参数值以生成 Uri 时使用其自己的格式,因此序列化参数以记录它们可能不会显示与放入 Uri 中的完全相同的内容。这就是为什么 IRestClient.BuildUri 方法很酷的原因是获取实际调用的 Uri(包括基本 url、替换的 url 段、添加的 queryString 参数等)。
  • 编辑: 还要记住,可能会发生序列化器 RestSharp 用于 body 的情况与此代码使用的不同,所以我猜代码可以调整为使用 body t 试过这个)。
  • 需要一些自定义代码才能在日志中对枚举值进行很好的描述。
  • request.JsonSerializer.Serialize() 用法可以移动以在测量中包括反序列化。

  • 这是一个基本的完整基类示例,带有日志记录(使用 NLog):
    using System;
    using System.Diagnostics;
    using System.Linq;
    using NLog;
    using Newtonsoft.Json;
    using RestSharp;
    
    namespace Apis
    {
        public abstract class RestApiBase
        {
            protected readonly IRestClient _restClient;
            protected readonly ILogger _logger;
    
            protected RestApiBase(IRestClient restClient, ILogger logger)
            {
                _restClient = restClient;
                _logger = logger;
            }
    
            protected virtual IRestResponse Execute(IRestRequest request)
            {
                IRestResponse response = null;
                var stopWatch = new Stopwatch();
    
                try
                {
                    stopWatch.Start();
                    response = _restClient.Execute(request);
                    stopWatch.Stop();
    
                    // CUSTOM CODE: Do more stuff here if you need to...
    
                    return response;
                }
                catch (Exception e)
                {
                    // Handle exceptions in your CUSTOM CODE (restSharp will never throw itself)
                }
                finally
                {
                    LogRequest(request, response, stopWatch.ElapsedMilliseconds);
                }
    
                return null;
            }
    
            protected virtual T Execute<T>(IRestRequest request) where T : new()
            {
                IRestResponse response = null;
                var stopWatch = new Stopwatch();
    
                try
                {
                    stopWatch.Start();
                    response = _restClient.Execute(request);
                    stopWatch.Stop();
    
                    // CUSTOM CODE: Do more stuff here if you need to...
    
                    // We can't use RestSharp deserialization because it could throw, and we need a clean response
                    // We need to implement our own deserialization.
                    var returnType = JsonConvert.DeserializeObject<T>(response.Content);
                    return returnType;
                }
                catch (Exception e)
                {
                    // Handle exceptions in your CUSTOM CODE (restSharp will never throw itself)
                    // Handle exceptions in deserialization
                }
                finally
                {
                    LogRequest(request, response, stopWatch.ElapsedMilliseconds);
                }
    
                return default(T);
            }
    
            private void LogRequest(IRestRequest request, IRestResponse response, long durationMs)
            {
                _logger.Trace(() =>
                {
                    var requestToLog = new
                    {
                        resource = request.Resource,
                        // Parameters are custom anonymous objects in order to have the parameter type as a nice string
                        // otherwise it will just show the enum value
                        parameters = request.Parameters.Select(parameter => new
                        {
                            name = parameter.Name,
                            value = parameter.Value,
                            type = parameter.Type.ToString()
                        }),
                        // ToString() here to have the method as a nice string otherwise it will just show the enum value
                        method = request.Method.ToString(),
                        // This will generate the actual Uri used in the request
                        uri = _restClient.BuildUri(request),
                    };
    
                    var responseToLog = new
                    {
                        statusCode = response.StatusCode,
                        content = response.Content,
                        headers = response.Headers,
                        // The Uri that actually responded (could be different from the requestUri if a redirection occurred)
                        responseUri = response.ResponseUri,
                        errorMessage = response.ErrorMessage,
                    };
    
                    return string.Format("Request completed in {0} ms, Request: {1}, Response: {2}",
                        durationMs, JsonConvert.SerializeObject(requestToLog),
                        JsonConvert.SerializeObject(responseToLog));
                });
            }
        }
    }
    

    这个类将记录如下内容(格式非常适合粘贴在这里):
    Request completed in 372 ms, Request : {
        "resource" : "/Event/Create/{hostId}/{startTime}",
        "parameters" : [{
                "name" : "hostId",
                "value" : "116644",
                "type" : "UrlSegment"
            }, {
                "name" : "startTime",
                "value" : "2016-05-18T19:48:58.9744911Z",
                "type" : "UrlSegment"
            }, {
                "name" : "application/json",
                "value" : "{\"durationMinutes\":720,\"seats\":100,\"title\":\"Hello StackOverflow!\"}",
                "type" : "RequestBody"
            }, {
                "name" : "api_key",
                "value" : "123456",
                "type" : "QueryString"
            }, {
                "name" : "Accept",
                "value" : "application/json, application/xml, text/json, text/x-json, text/javascript, text/xml",
                "type" : "HttpHeader"
            }
        ],
        "method" : "POST",
        "uri" : "http://127.0.0.1:8000/Event/Create/116644/2016-05-18T19%3A48%3A58.9744911Z?api_key=123456"
    }, Response : {
        "statusCode" : 200,
        "content" : "{\"eventId\":2000045,\"hostId\":116644,\"scheduledLength\":720,\"seatsReserved\":100,\"startTime\":\"2016-05-18T19:48:58.973Z\"",
        "headers" : [{
                "Name" : "Access-Control-Allow-Origin",
                "Value" : "*",
                "Type" : 3
            }, {
                "Name" : "Access-Control-Allow-Methods",
                "Value" : "POST, GET, OPTIONS, PUT, DELETE, HEAD",
                "Type" : 3
            }, {
                "Name" : "Access-Control-Allow-Headers",
                "Value" : "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept",
                "Type" : 3
            }, {
                "Name" : "Access-Control-Max-Age",
                "Value" : "1728000",
                "Type" : 3
            }, {
                "Name" : "Content-Length",
                "Value" : "1001",
                "Type" : 3
            }, {
                "Name" : "Content-Type",
                "Value" : "application/json",
                "Type" : 3
            }, {
                "Name" : "Date",
                "Value" : "Wed, 18 May 2016 17:44:16 GMT",
                "Type" : 3
            }
        ],
        "responseUri" : "http://127.0.0.1:8000/Event/Create/116644/2016-05-18T19%3A48%3A58.9744911Z?api_key=123456",
        "errorMessage" : null
    }
    

    希望你觉得这个有用!

    关于c# - RestSharp 打印原始请求和响应 header ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15683858/

    10-13 06:21