Blazor HttpClient 卡在 GetAsync 中

Blazor HttpClient stuck in GetAsync

我正在针对 Blazor 3.0.0-preview4-19216-03 的客户端 Blazor 应用中进行测试

剃须刀页面:

@page "/counter"
@using BlazorServiceTest
@inject IWebCrawlServiceAsync WebCrawler

<h1>Counter</h1>

<p>Current count: @debug</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    string debug = "";

    async void IncrementCount()
    {
        debug = await WebCrawler.GetWeb();
    }
}

依赖注入:

using BlazorServiceTest;
using Microsoft.AspNetCore.Components.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorServicesTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {   
            services.AddSingleton<IWebCrawlServiceAsync, WebCrawlServiceAsync>();            
        }

        public void Configure(IComponentsApplicationBuilder app)
        {
            app.AddComponent<App>("app");
        }
    }
}

服务:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

namespace BlazorServiceTest
{
    public interface IWebCrawlServiceAsync
    {
        Task<string> GetWeb();
    }

    public class WebCrawlServiceAsync : IWebCrawlServiceAsync
    {
        private HttpClient _client;    

        public WebCrawlServiceAsync(HttpClient client)
        {
            _client = client;
        }

        public async Task<string> GetWeb()
        {
            var response = await _client.GetAsync("https://postman-echo.com/response-headers?foo1=bar1&foo2=bar2");
            var result = await response.Content.ReadAsStringAsync();
            return result;
        }
    }
}

每当我点击增量计数时,都没有任何反应,并且对 GetWeb 的服务调用会卡在 GetAsync 调用中。

更新

如果我在 Chrome 的 WASM 调试器中调试 WebCrawler 服务,他会发出请求

但是响应部分是空的:

我怀疑它与async void有关。

您需要让处理程序 return 成为 Task,而不是 void

例如

@page "/counter"
@using BlazorServiceTest
@inject IWebCrawlServiceAsync WebCrawler

<h1>Counter</h1>

<p>Current count: @debug</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    string debug { get; set; } = "";

    async Task IncrementCount() { //<-- Note Change here
        debug = await WebCrawler.GetWeb();
    }
}

框架支持异步事件处理程序

引用GitHub Issue: Calling an async function via onclick

这可能是由于您无法控制的服务器上的 CORS 配置问题。我相信这个问题与 Blazor 无关。要验证这一点,请在您的应用程序中定义一个本地 json 文件,并使用您在应用程序中使用的相同代码访问它。

希望这能奏效...

更新

我不完全确定请求失败是由于 CORS 配置问题,至少不完全是。在我看来,它也与SSL/TLS有关。 此错误消息由 Fiddler 发出:

fiddler.network.https> HTTPS handshake to failed. System.IO.IOException Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. < An existing connection was forcibly closed by the remote host

底层连接已关闭,无法为 SSL/TLS 安全通道建立信任关系。

我想我会 post 在 github 中回答这个问题,以便更好地理解这里出了什么问题。

在 client-side 应用程序中,您只能访问自己的来源或支持 CORS 的网站。

为了验证这是您的问题,您可以尝试 https://postman-echo.com/response-headers?foo1=bar1&access-control-allow-origin=*,这可能有效。

但它只适用于该站点。您通常无法控制响应 headers。这不是解决办法。

所以,Blazor client-side 不是网络爬虫的好平台。 这同样适用于 JS 或 WASM 上的任何应用程序。

Blazor server-side 应该没有问题。或者使用 Web API 服务。


您可以在 Wasm 应用程序中尝试:

@page "/"
@inject HttpClient Http

<h1>Hello, world!</h1>
<div>
    <button class="btn btn-primary" @onclick="GetData1">With CORS</button>
    <button class="btn btn-primary" @onclick="GetData2">No CORS</button>
</div>
<div>@json</div>

@code
{
    string json = ".";

    async Task GetData1()
    {        
        json = await Http.GetStringAsync(
         "https://postman-echo.com/response-headers" + 
         "?foo1=bar1&access-control-allow-origin=*");
    }

    async Task GetData2()
    {
        json = "Getting w/o CORS... ";
        json = await Http.GetStringAsync(
          "https://postman-echo.com/response-headers?foo1=bar1");
    }
}