方法一:模板替換法(彈性高、支援資料繫承)
1. 模板檔 template.htm
<!DOCTYPE html>
<html>
<head><title>$title$</title></head>
<body>
<h1>$title$</h1>
<div>$content$</div>
</body>
</html>
2. 產生程式碼
protected void btnGenerate_Click(object sender, EventArgs e)
{
string templatePath = Server.MapPath("~/template.htm");
string outputDir = Server.MapPath("~/htm/");
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
string template = File.ReadAllText(templatePath, Encoding.GetEncoding("gb2312")); // 或 UTF-8
template = template.Replace("$title$", txtTitle.Text);
template = template.Replace("$content$", txtContent.Text);
string fileName = DateTime.Now.ToString("yyyyMMddHHmmss") + ".html";
string outputPath = Path.Combine(outputDir, fileName);
File.WriteAllText(outputPath, template, Encoding.GetEncoding("gb2312"));
Response.Write($"<a href='htm/{fileName}' target='_blank'>{fileName} 已生成</a>");
}
方法二:URL 直接抓取法(簡單、內容為即時渲染結果)
protected void btnFetchUrl_Click(object sender, EventArgs e)
{
string url = txtUrl.Text.Trim(); // 目標動態頁面 URL
string outputDir = Server.MapPath("~/htm/");
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
WebRequest req = WebRequest.Create(url);
using (WebResponse resp = req.GetResponse())
using (Stream stream = resp.GetResponseStream())
using (StreamReader sr = new StreamReader(stream, Encoding.UTF8))
{
string html = sr.ReadToEnd();
string fileName = DateTime.Now.ToString("yyyyMMddHHmmss") + ".html";
File.WriteAllText(Path.Combine(outputDir, fileName), html, Encoding.UTF8);
Response.Write($"<a href='htm/{fileName}' target='_blank'>{fileName} 已生成</a>");
}
}
比較與選擇建議
| 維度 | 模板替換 | URL 抓取 |
| 靈活度 | 高(可任意組合資料) | 低(只能拿已渲染結果) |
| 效能 | 極快(無 HTTP 往返) | 較慢(需完整請求管線) |
| 適用場景 | CMS 文章發佈、報表匯出、靜態化首頁 | 快速備份現有頁面、第三方頁面鏡像 |
| 動態資料 | 伺服器端直接組裝 | 需目標頁面已完成資料繫結 |
生產環境補充
- **靜態化佇列**:大量生成時寫入佇列,背景服務非同步處理,避免阻塞 Web 執行緒。
- **CDN 同步**:生成後自動推送至 CDN/物件儲存 (OSS/S3)。
- **快取失效**:生成新檔需同步清除舊檔快取(ETag/Last-Modified/版本號)。
- **編碼統一**:建議全站 UTF-8,避免 gb2312/Big5 混用導致亂碼。