/article/123.html 優於 /article.aspx?id=123public class UrlRewriter : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
try
{
string rawUrl = context.Request.RawUrl;
// 正則匹配 /show-12-34.html
Regex regex = new Regex(@"/show-(\d+)-(\d+)\..+", RegexOptions.IgnoreCase);
Match match = regex.Match(rawUrl, rawUrl.LastIndexOf('/'));
if (match.Success)
{
string realPath = $"~/aspx/show.aspx?type={match.Groups[1]}&id={match.Groups[2]}";
// Server.Execute 保持原請求上下文,支持 Session/表單驗證
context.Server.Execute(realPath);
}
else
{
context.Response.Redirect(context.Request.Url.ToString());
}
}
catch
{
context.Response.Redirect(context.Request.Url.ToString());
}
}
public bool IsReusable => false;
}
偽靜態頁面包含表單回發時,<form action="real.aspx?id=1"> 會暴露真實動態 URL。
namespace MyURL
{
public class MyOLPage : Page
{
protected override void Render(HtmlTextWriter writer)
{
// 替換 Writer 攔截 form action 輸出
TextWriter baseWriter = writer.InnerWriter;
if (writer is Html32TextWriter)
writer = new FormFixerHtml32TextWriter(baseWriter);
else
writer = new FormFixerHtmlTextWriter(baseWriter);
base.Render(writer);
}
}
internal class FormFixerHtml32TextWriter : Html32TextWriter
{
private readonly string _fakeUrl;
public FormFixerHtml32TextWriter(TextWriter writer) : base(writer)
{
_fakeUrl = HttpContext.Current.Request.RawUrl;
}
public override void WriteAttribute(string name, string value, bool encode)
{
if (_fakeUrl != null && string.Equals(name, "action", StringComparison.OrdinalIgnoreCase))
value = _fakeUrl;
base.WriteAttribute(name, value, encode);
}
}
// HtmlTextWriter 版本同理...
}
MyActionlessForm.dll 並引用public partial class MyPage : MyURL.MyOLPage下載源碼:Microsoft URL Rewriter,VS 編譯生成 DLL。
~/web/new/type/([0-9]+)\.html ~/web/new.aspx?id=$1 ~/web/index.html ~/web/index.aspx
*.html,可執行文件指向 aspnet_isapi.dll (如 C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll)| 維度 | IHttpHandler | 控制項適配器 | URLRewriter.dll |
|---|---|---|---|
| 實現複雜度 | 低 | 中 | 低(配置為主) |
| 正則靈活性 | 代碼控制 | 不涉及重寫 | 配置文件正則 |
| PostBack 修正 | 需額外處理 | 原生解決 | 需額外處理 |
| 性能 | 高 | 略有開銷 | 中等 |
| 維護性 | 代碼分散 | 繼承侵入性 | 集中配置 |
| 推薦場景 | 簡單重寫規則 | 表單回發頁面 | 規則多、頻變 |
// Startup.cs
app.UseRewriter(new RewriteOptions()
.AddRewrite(@"^show-(\d+)-(\d+)\.html$", "show.aspx?type=$1&id=$2", skipRemainingRules: true)
.AddRedirect(@"^old-page\.aspx$", "new-page.html"));
// 或使用 MapWhen 分支管道
app.MapWhen(ctx => ctx.Request.Path.Value.EndsWith(".html"),
branch => branch.Use(async (ctx, next) =>
{
// 自定義重寫邏輯
await next();
}));
根據項目架構、團隊習慣、規則複雜度選擇最合適方案,漸進式遷移至現代中間件體系。