如何解决 Blazor 中的 "TypeError: Failed to fetch" 错误?

27

我正在尝试从我的Blazor应用程序向我的ASP.NET Core API发送HTTP请求。 我在各处都设置了断点。 在API控制器上的操作方法返回后,应用程序会出现异常。 我对.NET有一定了解,但我无法解密错误消息。

Blazor HTTP调用:

var response = await _httpClient.GetStreamAsync($"Customer/GetAllCustomers");

ASP.NET Core API 控制器动作:

[HttpGet]
[Route("GetAllCustomers")]
public async Task<IEnumerable<Customer>> GetAllCustomersAsync()
{
    return await _service.GetAllCustomersAsync();
}

错误堆栈:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: TypeError: Failed to fetch
WebAssembly.JSException: TypeError: Failed to fetch
  at System.Net.Http.WebAssemblyHttpHandler.doFetch (System.Threading.Tasks.TaskCompletionSource`1[TResult] tcs, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x301ab40 + 0x00a30> in <filename unknown>:0 
  at System.Net.Http.WebAssemblyHttpHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x2ff3590 + 0x00174> in <filename unknown>:0 
  at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x2ff1e98 + 0x00160> in <filename unknown>:0 
  at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x2fc8a98 + 0x00182> in <filename unknown>:0 
  at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) <0x301ff08 + 0x00134> in <filename unknown>:0 
  at System.Net.Http.HttpClient.FinishGetStreamAsync (System.Threading.Tasks.Task`1[TResult] getTask) <0x2ffa720 + 0x000cc> in <filename unknown>:0 
  at WebClient.Services.LectureVideoService.GetAllLectureVideos (Content.Data.Enums.LessonType lessonType) [0x00040] in D:\AlbidersSoftware\CSharp\Albiders Content MS\Albiders\WebClient\Services\LectureVideoService.cs:21 
  at WebClient.Pages.MathAccList.OnInitializedAsync () [0x00026] in D:\AlbidersSoftware\CSharp\Albiders Content MS\Albiders\WebClient\Pages\MathAccList.razor:18 
  at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x2bed718 + 0x0013a> in <filename unknown>:0 
  at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask (System.Threading.Tasks.Task taskToHandle) <0x2e3a0b0 + 0x000b6> in <filename unknown>:0 

1
当我尝试从Blazor WASM调用同一个Web API端点时,出现了相同的错误。这是因为在服务器端没有正确配置CORS所致。但是,在单元测试中调用相同的Web API端点时,并没有发生错误。 - Mort
3个回答

13

未处理的异常导致组件无法渲染:TypeError: Failed to fetch

WebAssembly.JSException: TypeError: Failed to fetch

我在Blazor WebAssembly应用程序中进行了一项测试,向带有测试数据的操作方法发出请求,在我的端上运行良好。

[Route("[controller]")]
[ApiController]
public class CustomerController : ControllerBase
{
    [HttpGet]
    [Route("GetAllCustomers")]
    public async Task<IEnumerable<Customer>> GetAllCustomersAsync()
    {
        //for testing purpose

        return new List<Customer> { new Customer { Id = 1, Name = "Test1" }, new Customer { Id = 2, Name = "Test2" } };

        //return await _service.GetAllCustomersAsync();
    }
}

获取所有客户。.razor

@page "/getallcustomers"
@using BlazorWasmApp1.Shared
@inject HttpClient _httpClient

<h3>Customer List</h3>

@if (customers == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var customer in customers)
            {
                <tr>
                    <td>@customer.Id</td>
                    <td>@customer.Name</td>
                </tr>
            }
        </tbody>
    </table>
}


@code {
    private Customer[] customers;

    protected override async Task OnInitializedAsync()
    {
        //call external API
        //_httpClient.BaseAddress = new Uri("https://localhost:44312/");


        //your API action would return a collection of Customer
        //you can try to call .GetFromJsonAsync<Customer[]>() to get the expected data
        //rather than get stream
        customers = await _httpClient.GetFromJsonAsync<Customer[]>($"Customer/GetAllCustomers");
    }
}

测试结果

在此输入图片描述

若要解决问题,请尝试以下操作:

  1. 检查浏览器开发者工具网络选项卡中请求的 URL,并确保您正在向正确的端点发出请求

  2. 如果您的 ASP.NET Core Web API 项目托管在单独的站点上,请确保已配置并启用了 CORS 以允许您的 Blazor WebAssembly 应用程序发送请求,并确保该 API 正在运行


7

还要检查你的API是否从HTTP请求,如果是,请更改为HTTPS,它将正常工作。

在此输入图片描述


2

编辑说明:我刚才意识到我的原始答案是一个误导,所以我已经删除并替换了它。我的错误实际原因与您的问题有很大不同,但我将在此提供解决方案的摘要,因为这是出现此错误消息的第一篇帖子,可能会帮助其他人进行故障排除。

我正在构建一个Web Assembly Hosted项目,但有多个客户端,并一直试验将AddMicrosoftIdentityWebApi和AddMicrosoftIdentityWebApp组合在我的服务器项目中,如下所示。

Program.cs(服务器项目)

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))

只使用AddMicrosoftIdentityWebApi时,一切工作正常。但是,当我添加了AddMicrosoftIdentityWebApp并尝试从客户端调用我的api时,我遇到了您所识别的错误。

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: TypeError: Failed to fetch
System.Net.Http.HttpRequestException: TypeError: Failed to fetch
 ---> System.Runtime.InteropServices.JavaScript.JSException: TypeError: Failed to fetch
   at System.Net.Http.BrowserHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.BrowserHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__13`1[[BlazorApp14.Shared.WeatherForecast[], BlazorApp14.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at BlazorApp14.Client.Pages.FetchData.OnInitializedAsync() in C:\Temp\BlazorApp14\BlazorApp14\Client\Pages\FetchData.razor:line 50
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

如果我仔细观察,就会发现我的错误与你的不完全相同,但无论如何......
然后我注意到浏览器的开发工具中显示了一个额外的错误。
Access to fetch at 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=0e5f2876-c................... 
redirected from 'https://localhost:5001/WeatherForecast') from origin 'https://localhost:5001' has been blocked by CORS policy:
 Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

这使我深入了解了另一个问题,并在我的WebApi项目上设置了Cors等内容,但没有帮助。

然后我想也许可以在AddMicrosoftIdentityWebApi和AddMicrosoftIdentityWebApp调用中使用相同注册的AzureAD应用程序。 然而,这也不是问题所在。

事实证明,我的控制器上的[Authorize]属性无法选择要使用的身份验证方案并选择了“错误”的方案。 解决我的错误的简单方法是在Authorize属性中显式调用身份验证方案,如下所示。

   [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

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