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

Blazor WebAssembly如何为img等浏览器发起的请求附加访问令牌

解决方案

方案1:API支持令牌查询参数(最省事,性能最优)

该方案无需大幅修改前端逻辑,仅需要后端做兼容调整即可:

  • 后端令牌校验逻辑添加兼容:优先读取Authorization请求头,头不存在时尝试读取access_token查询参数作为令牌
  • 前端直接构造带令牌的图片地址即可:
<img class="card-image" src="@($"api/products/1/thumbnail?access_token={AccessToken}")">

注意:该方案必须在HTTPS环境下使用,HTTPS的查询参数会被加密传输,不存在令牌泄露风险。完全走浏览器原生资源加载逻辑,和普通静态资源加载性能完全一致,不会有任何卡顿问题。

方案2:用Blob URL替代Base64(无需改后端,解决现有卡顿)

你当前卡顿的核心原因是把图片转成Base64格式,Base64会让数据体积膨胀33%,且转码过程会占用大量CPU和内存。改用Blob URL可以完全解决该问题:

第一步:添加JS互操作方法

在wwwroot/index.html中添加全局JS方法:

window.createBlobUrl = async (stream) => {
    const response = new Response(stream);
    const blob = await response.blob();
    return URL.createObjectURL(blob);
}
window.revokeBlobUrl = (url) => {
    URL.revokeObjectURL(url);
}

第二步:修改TestProductView业务代码

public partial class TestProductView : ComponentBase, IAsyncDisposable
{
    [Parameter]
    public ProductMedia Product { get; set; }
    [Inject]
    private IHttpClientFactory HttpClientFactory { get; set; }
    [Inject]
    private IJSRuntime JSRuntime { get; set; }

    private string _blobUrl;
    private CancellationTokenSource _cts = new();
    // 全局缓存,避免重复加载相同图片
    private static ConcurrentDictionary<string, string> _imageCache = new();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && _blobUrl == null && Product.HasLink(StoreApiLinks.Product.Thumbnail, HttpMethod.Get))
        {
            var url = Product.GetUrl(StoreApiLinks.Product.Thumbnail, HttpMethod.Get);
            // 优先读取缓存
            if (_imageCache.TryGetValue(url, out var cachedUrl))
            {
                _blobUrl = cachedUrl;
                StateHasChanged();
                return;
            }
            try
            {
                var client = HttpClientFactory.CreateClient("api");
                using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, _cts.Token);
                if (response.IsSuccessStatusCode)
                {
                    await using var stream = await response.Content.ReadAsStreamAsync(_cts.Token);
                    _blobUrl = await JSRuntime.InvokeAsync<string>("createBlobUrl", _cts.Token, DotNetStreamReference.Create(stream));
                    _imageCache.TryAdd(url, _blobUrl);
                    StateHasChanged();
                }
            }
            catch (OperationCanceledException)
            {
                // 组件销毁时取消的请求直接忽略
            }
            catch
            {
                // 其他异常按需处理
            }
        }
    }

    public async ValueTask DisposeAsync()
    {
        _cts.Cancel();
        _cts.Dispose();
        // 全局缓存的BlobUrl不要销毁,其他组件还会复用
        // 如果不需要全局缓存可以在这里调用revokeBlobUrl释放资源
    }
}

第三步:修改razor模板

<div style="height:320px;width:300px;padding:8px;margin-right:15px;margin-bottom:15px; ">
  <img height='220' width="170" class="card-image" src="@_blobUrl" loading="lazy">
</div>

优化后消除了Base64转码开销,加上懒加载、无效请求自动取消、全局缓存的加持,滚动卡顿问题会完全消失。

方案3:Service Worker拦截加头(无侵入,性能最优)

如果既不想修改后端校验逻辑,也不想在前端单独处理每个图片的加载,可以注册Service Worker拦截所有发往API的资源请求,自动添加Authorization头:

  1. 在Service Worker脚本中添加拦截逻辑,从本地存储读取访问令牌添加到请求头中
  2. 前端img标签直接写原始src即可,无需任何修改,完全走浏览器原生加载逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:24:03