首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么GetFromJsonAsync不能解析JSON,但是ReadFromJsonAsync可以解析相同的JSON响应?

为什么GetFromJsonAsync不能解析JSON,但是ReadFromJsonAsync可以解析相同的JSON响应?
EN

Stack Overflow用户
提问于 2022-06-27 09:40:13
回答 1查看 634关注 0票数 1

我使用HttpClient向我的API项目发送请求,问题是GetFromJsonAsync方法无法解析响应JSON,但是如果我首先使用GetAsync方法获得响应,然后对其执行ReadFromJsonAsync,它将成功地解析JSON,为什么呢?

此代码不起作用:

代码语言:javascript
复制
public async Task<OperationResult<LoginNextStep>> SearchByEmailOrPhone(string emailOrPhone)
{
    // This fails to parse the response body
    var result = await _client.GetFromJsonAsync<ApiResult<OperationResult<LoginNextStep>>>
        ($"api/user/searchbyemailorphone/{emailOrPhone}", _jsonOptions);
    
    return result.Data;
}

这一次是:

代码语言:javascript
复制
public async Task<OperationResult<LoginNextStep>> SearchByEmailOrPhone(string emailOrPhone)
{
    var result = await _client.GetAsync($"api/user/searchbyemailorphone/{emailOrPhone}");

    // But this one works, with the same JSON
    var jsonResult = await result.Content.ReadFromJsonAsync
        <ApiResult<OperationResult<LoginNextStep>>>(_jsonOptions);

    return jsonResult.Data;
}

这是传递到方法中的_jsonOptions (通过构造函数注入类):

代码语言:javascript
复制
services.AddSingleton(new JsonSerializerOptions
{
    Converters = { new JsonStringEnumConverter() },
    PropertyNameCaseInsensitive = true
});

编辑:

我忘了说,这只发生在从API返回的特定JSON中,我的意思是它与ApiResutl的类型相同,但是由于一些奇怪的原因它无法解析它,在我的API项目中,我使用AspNetCoreRateLimit包来抑制垃圾邮件请求,在这个包中,如果它决定删除一个请求,它默认会返回一行文本,但是我可以覆盖它,当它删除一个请求时,我添加了我自己的返回类型,并且它是一个ApiResult,它是我的API的所有端点中的默认返回类型,(因此,我希望该包返回与其他端点相同的结果,其状态代码为429,以指示TooManyRequests)。

这是在删除垃圾邮件请求时覆盖的返回类型:

代码语言:javascript
复制
public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware
{
    public CustomIpRateLimitMiddleware(RequestDelegate next, IProcessingStrategy processingStrategy,
        IOptions<IpRateLimitOptions> options, IIpPolicyStore policyStore, IRateLimitConfiguration config,
        ILogger<IpRateLimitMiddleware> logger) : base(next, processingStrategy, options, policyStore, config, logger)
    {
    }

    public override async Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitRule rule,
        string retryAfter)
    {
        var result = new ApiResult
        {
            IsSuccessful = false,
            MetaData = new MetaData
            {
                ApiStatusCode = ApiStatusCode.TooManyRequests,
                Message = "You sent too many requests!!!"
            }
        };

        var jsonOptions = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } };
        var jsonResult = JsonSerializer.Serialize(result, jsonOptions);
        httpContext.Response.Headers["Retry-After"] = retryAfter;
        httpContext.Response.StatusCode = (int)ApiStatusCode.TooManyRequests;
        httpContext.Response.ContentType = "application/json";

        await httpContext.Response.WriteAsync(jsonResult);
        //return base.ReturnQuotaExceededResponse(httpContext, rule, retryAfter);
    }
}

为了产生这个问题,首先我手动尝试垃圾邮件,API会扼杀我的请求:

然后这是作为字符串的响应体,它与上面的图片相同:

ReadFromJsonAsync可以解析JSON:

但是GetFromJsonAsync的同一个请求失败了,它抛出一个HttpRequestException异常,(我想我昨天做了同样的事情,它会抛出一个像CouldNotParseJson这样的异常到ApiResult类型):

例外细节:

System.Net.Http.HttpRequestException HResult=0x80131500 Message=Response状态代码并不表示成功: 429 (请求太多)。System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() at System.Net.Http.Json.HttpClientJsonExtensions.d__13'1.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Source=System.Net.Http StackTrace (在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task任务)在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务)在System.Runtime.CompilerServices.TaskAwaiter'1.GetResult() at Shop.UI.Services.Users.UserService.d__14.MoveNext() in D:\VS Projects\Didikala\src\Shop\Shop.Presentation\Shop.UI\Services\Users\UserService.cs:line 99 这个异常最初被抛出在这个调用堆栈: System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() System.Net.Http.Json.HttpClientJsonExtensions.GetFromJsonAsyncCore(System.Threading.Tasks.Task,System.Text.Json.JsonSerializerOptions,( System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task) System.Runtime.CompilerServices.TaskAwaiter.GetResult() Shop.UI.Services.Users.UserService.SearchByEmailOrPhone(string) in UserService.cs )

似乎只有在响应成功时,GetFromJsonAsync才会尝试解析JSON,并且由于这个原因而失败,是否有任何方法让GetFromJsonAsync解析JSON响应,不管它是否成功?或者我只需分两步完成,即第一步GetAsync,然后用ReadFromJsonAsync解析它

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-28 10:44:35

GetFromJsonAsync调用EnsureSuccessStatusCode,因此它需要200-299之间的状态代码。另一方面,ReadFromJsonAsync没有。

相关代码这里

您的消息具有429状态,因此失败。

如果你想的话,你可以自己写分机。

代码语言:javascript
复制
public async Task<T> GetFromJsonAsync(string requestUri, JsonSerializerOptions options, CancellationToken cancellationToken = default)
{
    using (var response = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
    {
        var jsonResult = await result.Content.ReadFromJsonAsync<T>(_jsonOptions, cancellationToken);

        return jsonResult;
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72769971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档