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头:
- 在Service Worker脚本中添加拦截逻辑,从本地存储读取访问令牌添加到请求头中
- 前端img标签直接写原始src即可,无需任何修改,完全走浏览器原生加载逻辑。
内容的提问来源于stack exchange,提问作者mathi
相关产品推荐
相关产品推荐

