Blazor Server SPA被SEO爬虫访问时返回Soft 404问题求助
问题描述
当SEO爬虫直接访问Blazor Server SPA的内部URL/页面时,会返回「Soft 404」错误;但通过浏览器访问同一URL时,能正常返回预期页面内容且无错误。需要解决此「Soft 404」问题,让SEO爬虫能获取与浏览器相同的页面内容。
我们使用Blazor Server技术(ASP.NET Core 6.0)开发该SPA并部署在AWS EC2上,这是一个公开站点,通过NavigationManager根据路由提供动态页面内容,已提交包含所有导航URL的sitemap.xml文件用于SEO优化。
更多细节
- Blazor渲染模式:Server
- SignalR版本:Microsoft.AspNetCore.SignalR.Client 6.0.0
请求URL的响应内容
An error has occurred. This application may no longer respond until reloaded. Reload 🗙
Attempting to reconnect to the server... Reload
Reconnection failed. Try Reload the page if you're unable to reconnect.
Couldn't connect to the server Reload
相关代码文件
_Host.cshtml
@page "/" @namespace App.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = "_Layout"; } @* 如果我们使用ServerPreRender渲染模式,CustomAuthenticationStateProvider在预渲染阶段访问本地存储时会抛出异常。 注意:在Blazor Server的预渲染中,直到OnAfterRender生命周期方法才能执行任何JS互操作。 *@ <component type="typeof(App)" render-mode="Server" />
_Layout.cshtml
<head> <base href="~/" /> <component type="typeof(HeadOutlet)" render-mode="Server" /> </head> <body> @RenderBody() <div id="blazor-error-ui"> <environment include="Staging,Production"> 发生错误。此应用可能需要重新加载才能继续响应。 </environment> <environment include="Development"> 发生未处理的异常。请查看浏览器开发工具了解详情。 </environment> <a href="" class="reload">重新加载</a> <a class="dismiss">🗙</a> </div> <environment include="Staging,Production,Development"> <div id="components-reconnect-modal" class="my-reconnect-modal components-reconnect-hide"> <div class="show"> <p> 正在尝试重新连接服务器... <a href="" target="_top">重新加载</a> </p> </div> <div class="failed"> <p> 重新连接失败。如果无法重新连接,请尝试 <a href="" target="_top">重新加载</a>页面。 </p> </div> <div class="rejected"> <p> 无法连接到服务器 <a href="" target="_top">重新加载</a> </p> </div> </div> </environment> <script src="_framework/blazor.server.js"></script> </body> </html>
Program.cs
try { var builder = WebApplication.CreateBuilder(args); // 向容器添加服务。 builder.Services.AddRazorPages().AddNewtonsoftJson(); builder.Services.AddControllers(); builder.Services.AddServerSideBlazor().AddCircuitOptions(options => { // 将详细错误设置为'true',以便在开发环境中在浏览器显示详细的未处理异常消息。 options.DetailedErrors = true; }); // 其他依赖的Scoped和Transient服务及模型 builder.Services.AddSignalR(); var app = builder.Build(); // 配置HTTP请求管道。 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapBlazorHub(); app.MapHub<ChatHub>("/chathub"); endpoints.MapFallbackToPage("/_Host"); }); app.Run(); } catch (Exception ex) { Log.Fatal(ex, "应用启动失败。"); } finally { //Log.CloseAndFlush()仅需在控制台应用中调用一次,在应用退出前执行。 Log.CloseAndFlush(); }
我的理解
爬虫直接访问页面时,Blazor组件和SignalR连接默认无法建立,需要实现让爬虫获取页面内容而非重连错误。
解决方案
1. 修复预渲染认证问题,启用ServerPrerendered模式
当前使用的Server渲染模式不会预渲染页面内容,爬虫因不执行JS、无法建立SignalR连接,只能看到错误提示。启用ServerPrerendered模式可让服务器先渲染完整页面内容返回给爬虫,后续浏览器再建立SignalR连接交互。
针对预渲染时CustomAuthenticationStateProvider访问本地存储报错的问题,修改认证状态提供程序逻辑:
- 在
OnInitializedAsync(预渲染阶段)跳过依赖本地存储的操作,此时JS互操作不可用; - 在
OnAfterRenderAsync(JS可用阶段)再执行本地存储相关的认证逻辑。
修改_Host.cshtml中的渲染模式:
<component type="typeof(App)" render-mode="ServerPrerendered" />
2. 为爬虫请求返回静态化内容
如果预渲染仍有问题,可针对爬虫的User-Agent返回提前静态化的页面内容:
- 在Program.cs中添加中间件识别爬虫User-Agent;
- 匹配到爬虫时,返回对应URL的静态HTML文件(可通过定时任务或按需生成)。
示例中间件:
app.Use(async (context, next) => { var userAgent = context.Request.Headers.UserAgent.ToString(); var crawlerAgents = new[] { "Googlebot", "Bingbot", "Slurp", "DuckDuckBot" }; if (crawlerAgents.Any(agent => userAgent.Contains(agent, StringComparison.OrdinalIgnoreCase))) { var requestPath = context.Request.Path.HasValue ? context.Request.Path.Value.TrimStart('/') : "index"; var staticFilePath = Path.Combine(app.Environment.WebRootPath, "static", $"{requestPath}.html"); if (File.Exists(staticFilePath)) { await context.Response.SendFileAsync(staticFilePath); return; } } await next(); });
3. 确保路由正确映射
确认MapFallbackToPage配置正确,所有Blazor路由都能回退到/_Host,同时排查是否有其他中间件拦截爬虫请求返回错误。
4. 完善SEO元数据配置
利用HeadOutlet组件确保每个页面的PageTitle、Meta标签在预渲染时正确生成,让爬虫能抓取到完整的SEO相关内容。
内容的提问来源于stack exchange,提问作者Ananth MK

