Blazor HttpClient在执行GetAsync时卡住了。

4
我可以帮助您翻译以下内容:

我正在制作一个客户端 Blazor 应用程序,目标是 Blazor 3.0.0-preview4-19216-03。

Razor 页面:

@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服务,则请求正在进行。

enter image description here

但是响应部分为空:

enter image description here


1
你在哪里添加 HttpClient?还是它会自动添加? - Nkosi
它是由Blazor注入并进行了调整,以便在WASM环境中运行。我自己创建了一个新的HttpClient实例,但也没有起作用。 - Fritjof Berggren
3
我猜测这与async void有关。我正在阅读更多资料以确保。 - Nkosi
3个回答

1
我怀疑这与“async void”有关。
你需要让处理程序返回一个“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: 通过onclick调用异步函数


嗨Nkosi,感谢您的回答,但不幸的是它没有起作用,我添加了“private async Task IncrementCount()”,但没有任何区别。 - Fritjof Berggren
@Nkosi,你可以在事件中使用async void。我不确定是否需要调用this.StateHasChanged();,因为此方法在事件触发后始终会自动调用。 - enet
Blazor支持使用async Task来处理事件,这是非常可取的。如果您使用了async void,那么最好在结尾处加上StateHasChanged(),因为框架不会(也不能)自动执行该操作。 - H H

1

从客户端应用程序中,你只能访问自己的源或支持CORS的站点。

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

但它只适用于该站点。通常情况下,您无法控制响应标头。这不是一个解决方法。

因此,Blazor客户端只是不适合作为网络爬虫的平台。对于任何基于JS或WASM的应用程序也是如此。

Blazor服务器端应该没有问题。或者使用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");
    }
}

这是一个CORS问题,使用带有“access-control-allow-origin = *”的URL解决了问题。我将测试Blazor ServerSide,因为它看起来更健壮。感谢回答! - Fritjof Berggren
哦,是的,它是如何完成工作的?请给我们指点一下。上面URL中的“access-control-allow-origin = *”只是一个查询字符串参数,可以像另外两个参数一样回显。只需将此URL放入浏览器的地址栏中并按Enter键即可查看返回的JSON。您可以轻松地使用以下内容替换最后一个参数:“allow-origin = *”。 - enet
@Issac,请查看URL并阅读文档。这是一个专门用于测试API的网站。 - H H
那么,你能告诉我在URL中添加“access-control-allow-origin = *”会得到什么吗?你写道:“为了验证,你可以尝试……”另一个参数的添加有什么作用。原来有两个参数:foo1和foo2;现在你引入(或更改)一个新参数;就是这样。你意识到“access-control-allow-origin”的作用了吗? - enet
1
你还没有阅读 https://postman-echo.com 上的文档。你至少注意到 URL 中的 /response-headers 部分了吗? - H H
显示剩余6条评论

1
这可能是由于服务器上的CORS配置问题,您无法控制。我认为这个问题与Blazor无关。为了验证这一点,在您的应用程序中定义一个本地json文件,并使用与应用程序中使用的相同代码访问它。
希望这能起作用...
更新
我不确定请求失败是否仅由于CORS配置问题。在我看来,它也与SSL / TLS有关。此错误消息由Fiddler发出:
fiddler.network.https> HTTPS握手失败。 System.IO.IOException 无法从传输中读取数据 连接:远程主机强制关闭现有连接。 <现有连接被远程主机强制关闭
底层连接已关闭,无法建立SSL / TLS安全信任关系。
我想我会在github上发布这个问题,以更好地了解出了什么问题。

1
“@etragu说:“它是由Blazor注入并进行了调整,以便在WASM环境中运行。”抱歉,没有区别……我之前没有注意到代码…” - enet

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