对于现在流行网站来说,内容的访问路径只使用 id 已经不能满足了,以下提供一个简单的中间件可以自由的用数据库来自定义网站内容的友好链接,此方法完全不需要您再为每个不同的表加友好链接字段,通用性更好。
记录表
/// <summary>
/// 短链接记录,对应 shortlinks 表
/// </summary>
[Table("shortlinks")]
public class ShortLink
{
[Key]
[StringLength(128)]
public string Path { get; set; }
[Required]
[StringLength(1024)]
public string Link { get; set; }
[StringLength(45)]
public string RefType { get; set; }
[StringLength(32)]
public string RefId { get; set; }
public bool Enable { get; set; }
}
中间件
/// <summary>
/// 基于数据库中 ShortLink 的设置重写请求
/// </summary>
class ShortLinkMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ShortLinkMiddleware> _logger;
public ShortLinkMiddleware(RequestDelegate next, ILogger<ShortLinkMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, IMemoryCache cache)
{
// 从缓存或数据库中读取短链接对应关系
var links = await cache.GetOrCreateAsync(typeof(ShortLinkMiddleware), async e =>
{
// 设置缓存 15 分钟
e.SetAbsoluteExpiration(TimeSpan.FromMinutes(15));
// 获取数据访问上下文
var db = context.RequestServices.GetRequiredService<AppDbContext>();
// 从数据库读取启用状态的短链接
return await db.ShortLinks.Where(s=>s.Enable).ToListAsync();
});
// 获取当前访问路径适配的短链接记录
var matchLink = links.FirstOrDefault(l => l.Path == context.Request.Path);
if(matchLink != null)
{
// 输出转换日志并修改当前请求的 Path
_logger.Log(LogLevel.Trace, $"ShortLink {matchLink.Path} To {matchLink.Link}");
context.Request.Path = matchLink.Link;
}
// 调用管道中的下一个委托或中间件
await _next(context);
}
}
注册中间件
在 Startup.cs 的 Configure 方法中加入 app.UseMiddleware<ShortLinkMiddleware>();