PAYATHON 2026

MAUI Hybrid 中 BlazorWebView 的 HTTP GET 请求为何无法完成?

排障赵师傅

先修正 API 地址,再检查 HTTPS 和认证

请求地址中的 https://localhost:7087 需要先修改。在 Android 模拟器中,localhost 指向模拟器自身,不会自动指向运行 Web 项目的开发电脑。如果没有配置端口转发,标准 Android 模拟器应使用 10.0.2.2 访问宿主机的本地服务。Microsoft 的本地 Web 服务连接说明

普通 HTTP GET 不需要额外实现 WebChromeClient。定位权限、自定义媒体权限回调和文件访问设置都无法解决 API 地址问题。

仅凭现有日志,还无法确定全部故障原因。修改地址后,需要继续检查 HTTPS 证书、CORS,以及 .RequireAuthorization() 要求的登录凭据。

日志中的“未找到响应内容”是什么意思?

这几行日志来自 BlazorWebView 的资源处理流程:

Intercepting request for ...
Handling web request to URI ...
Response content was not found ...

BlazorWebView 要为页面提供应用内的静态资源,因此会先检查本地资源提供程序能否响应请求。

在 .NET MAUI 10.0.0 的 Android 实现中,如果本地资源处理没有返回响应,代码会继续调用 base.ShouldInterceptRequest(view, request),让 WebView 按正常流程处理请求。因此,“Response content was not found”不能直接说明请求被吞掉,也不能说明服务端 API 返回了 404。对应源码

日志后两行没有查询字符串,是因为这段资源检查代码主动移除了查询字符串,不能据此认定 range 和 selectedItemId 丢失。

DevTools 的“Provisional headers are shown”也不能指出具体的故障原因。还需要结合 Console 中的网络错误、Network 面板和服务端访问日志判断。Chrome DevTools 说明

第一步:让请求到达 Web 项目

如果 Web 项目在开发电脑上监听:

https://localhost:7087

Android 模拟器中的 API 基地址应先改为:

// 适用于标准 Android 模拟器访问开发电脑的本地服务。
// 前提:服务确实监听 HTTPS 7087,且证书验证能够通过。
const baseUrl = "https://10.0.2.2:7087";

这里只修改主机地址,端口仍以 Web 项目的实际监听配置为准。只有服务确实在该端口提供 HTTP 时,才能把 https 改成 http 并沿用同一端口。

还需要确认:

  • Web 项目已经独立启动。运行 Mobile 项目不等于启动 Web 服务。
  • 服务端的监听地址、端口和防火墙规则允许模拟器访问。
  • 如果使用真机,应改用真机可达的局域网地址或 HTTPS 域名。10.0.2.2 是模拟器提供的特殊地址。

Shared 项目只共享组件和代码,不会把 Web 项目中通过 MapGet 注册的 API 一起托管到手机上。

第二步:处理 HTTPS 证书

地址改为 10.0.2.2 后,仍可能遇到证书错误:

  • 开发电脑信任 ASP.NET Core 开发证书,不代表 Android WebView 也信任它。
  • 如果证书只适用于 localhost,通过 10.0.2.2 访问还可能出现名称不匹配。

这些问题发生在 TLS 建立阶段,修改 Access-Control-Allow-Origin 无法解决。MAUI 本地 HTTPS 连接说明

可以使用设备信任且名称匹配的 HTTPS 证书,也可以通过提供有效 HTTPS 地址的开发隧道访问服务。

这里的 $.get 使用 WebView 的网络栈。在 C# 中设置 HttpClientHandler.ServerCertificateCustomValidationCallback,不会改变 jQuery 请求的证书验证行为。

如果临时改用 HTTP 排查,还要处理 Android 的明文流量策略,以及 HTTPS 页面请求 HTTP API 时可能遇到的 mixed content 限制。仅修改 URL 不一定能让请求成功。

第三步:补上失败回调

原代码只处理成功结果。请求失败时,DOCUMENTS RECEIVED 不会输出,但仅凭这一点,无法区分连接失败、认证失败或 JSON 解析失败。

可以改为:

const requestData = [];

console.log("Page origin:", window.location.origin);
console.log("API URL:", baseUrl + "/api/documents");

$.ajax({
    url: baseUrl + "/api/documents",
    method: "GET",
    data: {
        range: distance,
        selectedItemId: selectedItemId
    },
    dataType: "json",
    timeout: 15000
})
.done(function (data) {
    console.log("DOCUMENTS RECEIVED");

    $.each(data, function (index, value) {
        requestData.push({
            name: value.name,
            displayIndex: value.displayIndex,
            itemId: value.id
        });
    });
})
.fail(function (xhr, textStatus, errorThrown) {
    console.error("GET failed", {
        status: xhr.status,
        textStatus: textStatus,
        error: errorThrown,
        responseText: xhr.responseText
    });
});

xhr.status === 0 也不能单独确定原因。网络连接、TLS、CORS 或请求取消等情况,都需要进一步查看 Console 中的错误。设置超时只是为了限制等待时间。

排查时还应检查服务端是否收到请求。如果没有任何访问记录,先检查地址和连接;如果服务端已经返回响应,再根据状态码处理后续问题。

第四步:按 WebView 的实际 Origin 配置 CORS

Web 项目中的页面调用自己的 API,通常是同源请求。Hybrid 中的页面由 BlazorWebView 承载,调用远程 API 时则可能跨源,两种运行方式的网络条件有所不同。

CORS 允许的 Origin 应根据 WebView 实际发出的 Origin 设置,可以结合 window.location.origin 和请求头确认。这个值是发起请求的页面来源,不是 API 的目标地址。

可以通过配置项提供这个值,避免写死某个框架默认地址:

var hybridOrigin = builder.Configuration["HybridOrigin"]
    ?? throw new InvalidOperationException("HybridOrigin is required.");

builder.Services.AddCors(options =>
{
    options.AddPolicy("HybridApi", policy =>
    {
        policy.WithOrigins(hybridOrigin)
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

// 保留现有服务注册和应用配置。
var app = builder.Build();

app.UseRouting();
app.UseCors("HybridApi");
app.UseAuthentication();
app.UseAuthorization();

// 在此保留现有 API 映射。

HybridOrigin 应填写完整的 scheme、host 和必要的 port,不带路径或末尾 /。UseCors 应放在路由之后、授权之前。ASP.NET Core CORS 配置说明

仅给成功响应手动添加 Access-Control-Allow-Origin,无法完整处理预检请求、认证失败等响应,使用 CORS 中间件更合适。

第五步:确认受保护 API 的登录凭据

该接口包含:

.RequireAuthorization();

即使网络和 CORS 都已正常,Mobile 端仍需提供服务端认可的身份。

电脑浏览器中的登录状态不会自动带到 Android WebView 中,共享 Razor 组件也不会自动共享浏览器 Cookie。

如果服务使用 Cookie 认证,跨源 jQuery 请求需要设置:

xhrFields: {
    withCredentials: true
}

服务端策略则需要在明确的 WithOrigins(...) 基础上添加:

.AllowCredentials()

AllowCredentials() 不能与 AllowAnyOrigin() 配合使用。跨源凭据配置说明

这些设置只允许发送符合条件的 Cookie,不会创建登录状态。还需确认 WebView 已完成登录,并检查 Cookie 的 Domain、Path、SameSite、Secure 属性及第三方 Cookie 策略。

如果采用 Bearer Token,应通过既定认证流程取得令牌,并随请求发送有效的 Authorization 请求头。

是否需要继续自定义 BlazorWebView?

对于这个 GET 请求,目前没有证据表明需要继续扩展 PermissionManagingBlazorWebChromeClient。定位权限功能可以保留,但增加 WebView 权限无法修复这里的网络连接问题。

以下两个设置也不适用于解决这类问题:

AllowFileAccessFromFileURLs
AllowUniversalAccessFromFileURLs

它们控制 file:// 内容的访问行为,无法解决模拟器地址、HTTPS 信任或 API 授权问题。这些设置在 Android API 中也已弃用,不应作为跨源 API 请求的通用解决办法。Android WebSettings 文档

现有信息不足以将问题归因于 jQuery 4.0.0、VS2026 或某个 .NET 10 缺陷。

备注:内容仅供参考。