You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor带参数请求报表后如何在新标签页打开返回的PDF/Excel文件

步骤1:调整服务层返回结构

首先修改现有服务层的返回值,把文件字节数组和响应的MIME类型一起返回,方便后续前端处理:

// 新增自定义文件响应类
public class FileResponse
{
    public byte[] Content { get; set; }
    public string ContentType { get; set; }
    public bool IsSuccess { get; set; }
}

// 修改SendRequest方法返回类型
private async Task<FileResponse> SendRequest(HttpRequestMessage request)
{
    var user = await localStorageService.GetItem<string>("access_token");
    var isApiUrl = !request.RequestUri.IsAbsoluteUri;
    if (user != null && isApiUrl)
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", user);

    using var response = await httpClient.SendAsync(request);
    var content = await response.Content.ReadAsByteArrayAsync();

    if (response.StatusCode == HttpStatusCode.Unauthorized)
    {
        navigationManager.NavigateTo("login");
        return new FileResponse { IsSuccess = false };
    }

    if (response.StatusCode == HttpStatusCode.BadRequest)
    {
        var reply = Encoding.UTF8.GetString(content);
        var oReply = JsonSerializer.Deserialize<ErrorReply>(reply);
        await helperService.InvokeAlert("Sorry...", $@"{oReply.Error[0].ToString()}", true);
        return new FileResponse { IsSuccess = false };
    }

    return new FileResponse 
    { 
        IsSuccess = true, 
        Content = content, 
        ContentType = response.Content.Headers.ContentType?.ToString() ?? "application/octet-stream"
    };
}

// 同步修改Post方法返回类型
public async Task<FileResponse> Post(string uri, object value)
{
    var request = new HttpRequestMessage(HttpMethod.Post, uri);
    request.Content = new StringContent(JsonSerializer.Serialize(value), Encoding.UTF8, "application/json");
    return await SendRequest(request);
}

// 同步修改GetDailyAttendances方法返回类型
public async Task<FileResponse> GetDailyAttendances(FetchEmployeeAttendance parameter)
{
    return await httpService.Post($@"api/Reports", parameter);
}

步骤2:添加JS互操作方法

在Blazor WebAssembly的wwwroot/index.html(如果是Blazor Server则是Pages/_Layout.cshtml/_Host.cshtml)的<script>节点中加入如下JS函数,用于将字节流转为Blob并在新标签页打开:

function openFileInNewTab(fileBytes, mimeType) {
    // 把Blazor传来的Uint8Array转为Blob
    const blob = new Blob([fileBytes], { type: mimeType });
    const fileUrl = URL.createObjectURL(blob);
    // 新标签页打开文件
    window.open(fileUrl, '_blank');
    // 1分钟后释放Blob URL避免内存泄漏
    setTimeout(() => URL.revokeObjectURL(fileUrl), 60000);
}

步骤3:修改Blazor组件代码

在你的报表组件中注入IJSRuntime,调整GetReport方法调用JS打开文件:

// 注入JS运行时
[Inject]
public IJSRuntime JSRuntime { get; set; }

protected async Task GetReport()
{
    var dateFrom = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
    var dateTo = dateFrom.AddDays(1);
    var parameter = new FetchEmployeeAttendance
    {
        DateFrom = dateFrom,
        DateTo = dateTo,
        ReportType = 1,
        UserId = 2
    };
    var result = await DailyTimeInService.GetDailyAttendances(parameter);
    if(result.IsSuccess)
    {
        // 调用JS方法打开文件
        await JSRuntime.InvokeVoidAsync("openFileInNewTab", result.Content, result.ContentType);
    }
}

注意事项

  • 如果你生成的是xlsx格式的Excel文件,可以将服务端返回的ContentType改为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,兼容性更好
  • 该操作由用户点击按钮主动触发,浏览器默认不会拦截新标签页,若出现拦截可引导用户允许站点弹窗
  • 代码中加入了1分钟后自动释放Blob URL的逻辑,避免内存占用过高

内容的提问来源于stack exchange,提问作者Ibanez1408

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 18:27:00