How to get the JSON error message from HttpRequest

2019-02-19 11:56发布

问题:

I have a situation where in I have to extract a Response(HttpResponseMessage) in a catch statement but that I suppose can't be done (using await in catch). Also if i do it after catch , the HttpResponseMessage message gets "Disposed". Code:

 private async void MakeHttpClientPostRequest()
 {
     HttpResponseMessage response = null;
     try
     {
         HttpClient httpClient = new HttpClient();
         httpClient.Timeout = TimeSpan.FromSeconds(15);
         HttpContent httpContent = null;
         if (postJSON != null)
         {
             httpContent = new StringContent(postJSON);
             httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
         }

         response = await httpClient.PostAsync(url, httpContent);
         if (response != null)
         {
             response.EnsureSuccessStatusCode();
             netResults = await response.Content.ReadAsStringAsync();
         }

         if (this.convertedType != null)
         {
             MemoryStream assetReader = GetMemoryStreamFromString(netResults);
             assetReader.Position = 0;
             object value = fromJSON(assetReader, this.convertedType);
             networkReqSuccessWithObjectCallback(this, value);
         }
         else
         {
             //Return netResult as string.
             networkReqSuccessWithStringCallback(this, netResults);
         }
     }

     catch (TaskCanceledException)
     {
         ErrorException ee = null;
         ee = new ErrorException("RequestTimeOut");
         NotifyNetworkDelegates(ee);
     }
     catch (HttpRequestException ex)
     {
         //HERE I have to extract the JSON string send by the server
     }
     catch (Exception)
     {
     }
}

What can be done here ?


Update Previous approach using HttpWebRequest :

public void MakePostWebRequest()
{
    //WebCalls using HttpWebrequest.
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
    request.CookieContainer = new CookieContainer();
    request.ContentType = "application/json";
    request.Method = "POST";
    requestState = RequestState.ERequestStarted;
    asyncResult = request.BeginGetRequestStream(new AsyncCallback(GetRequestStream), request);
}


private void GetRequestStream(IAsyncResult asyncResult)
{
    HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
    {
        try
        {
            Stream requestStream = request.EndGetRequestStream(asyncResult);
            if (request != null)
            {
                using (requestStream)
                {
                    StreamWriter writer = new StreamWriter(requestStream);
                    writer.Write(postJSON);
                    writer.Flush();
                }
            }
        }
        catch (WebException we)
        {
        }
    }
}

private void GetResponseStream(IAsyncResult asyncResult)
{
    requestState = RequestState.EResponseStream;

    HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
    HttpWebResponse response;
    try
    {
        response = (HttpWebResponse)request.EndGetResponse(asyncResult);
        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            netResults = reader.ReadToEnd();
        }
        requestState = RequestState.ERequestCompleted;
    }
    catch (WebException we)
    {
        // failure
        ErrorException ee = null;
        response = we.Response as HttpWebResponse;
        if (response != null)
        {
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                //HERE I'm getting the json error message
                netResults = reader.ReadToEnd();
            }
        }
    }
    catch (Exception e)
    {
        networkReqFailedCallback(this, e);
    }
}

回答1:

I strongly suspect the problem is that the exception is actually thrown by your call to EnsureSuccessStatusCode, whose documentation contains:

If the Content is not null, this method will also call Dispose to free managed and unmanaged resources.

Basically it sounds like you shouldn't be using that method to determine the success or failure if you need the content on failure.

Just check the status code yourself, and use the content appropriately based on that code. Note that in your catch block response could very easily be null, if the request failed completely.



回答2:

The correct way of doing this is within the try block itself

try
{
    response = await httpClient.PostAsync(url, httpContent);

    netResults = await response.Content.ReadAsStringAsync();
     //do something with the result
}
catch(HttpRequestException ex)
{
     // catch any exception here
}

Catch blocks are used to handle exceptional conditions. Rethrow if required, but should be avoided.



回答3:

Response should be available only in case when a remote server actually responded. If Response is null (as I understood this is your case), it means that because of some reasons the request wasn't delivered or response wasn't received (doesn't metter which response - with code 200 (OK) or any other code (ERROR)). Please check the error code (we.Status). Ensure it is equal WebExceptionStatus.ProtocolError (i.e., the server responded with error); otherwise, some some other error occurred and Response should not be available.