如何在Razor Page中用标题替代ID显示在URL中?
在.NET 6 Razor Pages中实现SEO友好的博客详情URL(替换ID为标题)
要把博客详情页的URL从/blog-details/4改成包含文章标题的SEO友好格式,比如/blog-details/wo-de-di-yi-pian-net-bo-ke,可以按以下步骤操作:
1. 给文章添加Slug字段
首先在博客文章的数据模型(比如BlogPost)里新增Slug字段,类型为string,用来存储处理后的URL友好标题。这个字段需要满足:
- 仅包含小写字母、数字、连字符(-)
- 全局唯一(避免不同文章URL冲突)
- 能对应到唯一一篇文章
新增文章时可以自动生成Slug,也允许后台手动调整(比如优化关键词)。
2. 修改Razor Page的路由规则
找到博客详情页(比如BlogDetails.cshtml),在页面顶部修改路由模板:
@page "/blog-details/{slug}"
或者在页面模型类上通过[PageRoute]属性配置:
[PageRoute("/blog-details/{slug}")] public class BlogDetailsModel : PageModel { // ... 模型逻辑 }
3. 调整详情页的查询逻辑
原来的OnGet方法通过id查询文章,现在改成用slug查询:
private readonly AppDbContext _context; public BlogDetailsModel(AppDbContext context) { _context = context; } public BlogPost BlogPost { get; set; } public async Task<IActionResult> OnGetAsync(string slug) { if (string.IsNullOrWhiteSpace(slug)) { return NotFound(); } BlogPost = await _context.BlogPosts .FirstOrDefaultAsync(p => p.Slug == slug); if (BlogPost == null) { return NotFound(); } return Page(); }
4. 更新文章列表页的链接
在文章列表页(比如BlogList.cshtml),把原来指向详情页的链接从id参数换成slug参数:
@foreach (var post in Model.BlogPosts) { <a asp-page="/BlogDetails" asp-route-slug="@post.Slug">@post.Title</a> }
如果用代码生成URL,就改成:
var detailUrl = Url.Page("/BlogDetails", new { slug = post.Slug });
5. 实现Slug自动生成逻辑
写一个工具方法把文章标题转换成符合要求的Slug,示例代码:
using System.Globalization; using System.Text; using System.Text.RegularExpressions; public static class SlugHelper { public static string GenerateSlug(string title) { // 移除重音符号 var normalizedTitle = title.Normalize(NormalizationForm.FormD); var sb = new StringBuilder(); foreach (var c in normalizedTitle) { var category = CharUnicodeInfo.GetUnicodeCategory(c); if (category != UnicodeCategory.NonSpacingMark) { sb.Append(c); } } // 移除特殊字符,替换空格为连字符,转小写 var slug = sb.ToString().Normalize(NormalizationForm.FormC); slug = Regex.Replace(slug, @"[^a-zA-Z0-9\s-]", ""); slug = Regex.Replace(slug, @"\s+", "-").ToLower(); slug = Regex.Replace(slug, @"-+", "-").Trim('-'); return slug; } }
生成Slug后要检查数据库是否已存在相同值,如果存在可以追加数字(比如my-first-post-1)来保证唯一性。
6. 可选:兼容旧ID路由(避免404)
如果之前的ID格式URL已经被搜索引擎收录,为了不影响SEO,可以添加兼容逻辑:
- 修改路由模板支持两种格式:
@page "/blog-details/{identifier}" - 调整
OnGet方法判断参数是ID还是Slug,并做301重定向(传递SEO权重):public async Task<IActionResult> OnGetAsync(string identifier) { BlogPost post = null; if (int.TryParse(identifier, out int id)) { post = await _context.BlogPosts.FirstOrDefaultAsync(p => p.Id == id); } else { post = await _context.BlogPosts.FirstOrDefaultAsync(p => p.Slug == identifier); } if (post == null) { return NotFound(); } // 如果是通过ID访问,301重定向到Slug URL if (int.TryParse(identifier, out _)) { return RedirectToPage("/BlogDetails", new { slug = post.Slug }, permanent: true); } BlogPost = post; return Page(); }
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

