2014-12-29 2 views
6

Я делаю приложение, в котором клиент выполняет запросы к серверу. Сервер написан в node.js и клиенте в .NET с использованием flurl.Http.Неверная ошибка Flurl.Http

Когда запрос на сервере выходит из строя, всегда полезно создать настраиваемое сообщение об ошибке. Что-то вроде этого:

request.respond(500, { message: "targetid is mandatory" }); 

Однако это вызывает FlurlHttpException на стороне клиента и информации JSON в ответ теряется.

Как я могу получить эту информацию JSON, если с сервера получен неверный код ответа?

+0

Я думаю, что мой [новый ответ] (http://stackoverflow.com/a/28332184/62600) должен быть тем, что вы ищете. –

ответ

7

Я только что опубликовал обновление Flurl.Http, что делает дело с ответами ошибок в целом лот Полегче.Вот пример:

try { 
    var t = await "http://api.com".GetJsonAsync<T>(); 
} 
catch (FlurlHttpException ex) { 
    var error = ex.GetResponseJson<TError>(); 
} 

Есть несколько вариантов:

ex.GetResponseString(); 
ex.GetResponseJson(); // returns a dynamic 

Обратите внимание, что вам не нужно await тела реакция на ошибку. Поскольку await Внутри блока catch не поддерживается блок C# 4.5, я не хотел его здесь. Однако до сих пор нет блокировки; тело реакции на ошибку ожидается и зафиксировано как часть первоначального вызова. (Так как упреждающий захват тела ответа как строки в нормальных условиях может быть хитом производительности, я делаю это только для неуспешных ответов, в которые будет выброшен FlurlHttpException. В будущем я могу подумать о том, чтобы сделать это поведение настраиваемым.)

Эти усовершенствования были добавлены в версию 0.5.0 и доступны по адресу NuGet.

0

Я решил эту проблему, отредактировав исходный код Flurl. В файле FlurlMessageHandler.cs вы найдете метод IsErrorCondition, который проверяет, произошла ли ошибка. Всякий раз, когда в ответе нет кода 2xx, это рассматривается как ошибка, эта часть я удалил из te-кода, и теперь я вручную проверяю, имеет ли ответ код succes.

0

Вы можете получить тело несостоявшегося ответа, хотя FlurlHttpException.Call, который является экземпляром HttpCall, диагностический объект, который содержит (помимо всего прочего) необработанный HttpRequestMessage и HttpResponseMessage.

Получение тело из ответа требует вызова асинхронной, и, к сожалению, вы не можете await внутри catch блока, так что я бы предложил захватить отказавший вызов внутри этого блока catch и await после усопшего ответа. Что-то вроде этого:

HttpCall failedCall = null; 

try { 
    await url.GetAsync(); 
} 
catch (FlurlHttpException ex) { 
    failedCall = ex.Call; 
} 

if (failedCall != null && failedCall.Response != null) { 
    var body = await failedCall.Response.Content.ReadAsStringAsync(); 
    // body now contains the full text of the failed response. 
} 

Хотя Flurl первенствует на получение вас от базового URL для ответа POCO с минимальным количеством шума, как это возможно, это правда, становится все более шумным, когда вам придется иметь дело с телом неудавшегося ответа. Я открыл note-to-self, чтобы узнать, могу ли я найти несколько ярлыков здесь. Не стесняйтесь комментировать любые идеи, которые у вас могут быть.

+0

В моем ответе я покажу, как сохранить асинхронный поток. –

+0

@ LayGonzález Если «держать асинхронный поток» вы ожидаете в блоке catch, вы не можете сделать это в текущей (поддерживаемой) версии языка/компилятора, но я понимаю, что это [идет] (http: // blog. stephencleary.com/2014/06/await-in-catch-and-finally.html). –

0

Я считаю, что интересно обрабатывать все ошибки HTTP как исключения. Не уверен, что это лучшая практика, но я попробовал.

То, что я сделал что-то вроде этого:

public static async Task<User> LoginWithEmail (string email, string password){ 
    try{ 
    return await "http://myapi.com/login" 
       .AppendPathSegment ("login") 
       .SetQueryParams (new {email = email, password = password}) 
       .WithHeader ("Accept", "application/json") 
       .GetJsonAsync<User>(); 
    }catch (FlurlHttpException e) { 
    return await e.Call.Response.Content.ReadAsStringAsync() 
        .ContinueWith<User> ((contentAsync) => { 
         throw new MyApiException(JsonConvert.DeserializeObject<MyApiError> (contentAsync.Result)); }); 
    } 
} 

Это позволяет обрабатывать случаи успеха и ошибки, как это:

async void FakeLogin() 
{ 
    try{ 
     User user = await LoginWithEmail ("[email protected]", "fakePassword"); 
    } 
    catch(MyApiException e) { 
     MyApiError = e.Error; 
    } 
} 

В принципе

Для случая FlurlHttpException , Я делаю продолжение для ReadAsStringAsync, где объявляю продолжение возвращать пользователя, но внутри продолжения я всегда выбросить исключение.

Кроме того

Вы можете реорганизовать обработку исключения быть как:

catch (FlurlHttpException e) { 
    return await MyApiException.FromFlurlException<User>(e); 
} 
+0

Какую версию Visual Studio вы используете? Это * может * компилироваться в предварительном просмотре 2015 года (не пробовал), но не будет в любом поддерживаемом релизе, потому что [вы не можете ждать внутри блока catch] (http://stackoverflow.com/questions/8868123/await -в-улов-блок). –

+0

Я использую Xamarin .Net PCL 78, который, я считаю, является .net 4.5. Он компилируется и запускается, но теперь я не уверен, что работает как ожидалось (асинхронно). –

+0

@ToddMenier Теперь я могу подтвердить, что я смог скомпилировать его, потому что использовал Mono. Visual Studio .Net не позволит использовать ожидание внутри блока catch, как вы сказали. –

Смежные вопросы