首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 2.0 輸出文字格式流:IHttpHandler (.ashx) 動態生成 HTML 內容

     編輯:關於ASP.NET

應用場景:動態內容無需實體檔案

當頁面內容來源於資料庫、運算產生、或需依請求參數動態組裝時,傳統做法產生暫存 .aspx/.html 檔案再導向,會造成磁碟 I/O、暫存檔清理、併發衝突等問題。**IHttpHandler (.ashx) 直接輸出記憶體流至 Response**,零磁碟落地、高效能、天然支援串流。

.ashx 實作完整範例

HtmlHandler.ashx

<%@ WebHandler Language="C#" Class="HtmlHandler" %>
using System;
using System.IO;
using System.Web;

public class HtmlHandler : IHttpHandler
{
    public bool IsReusable => true; // 無狀態,可重用

    public void ProcessRequest(HttpContext context)
    {
        HttpResponse response = context.Response;
        HttpRequest request = context.Request;

        // 1. 設定回應標頭
        response.ContentType = "text/html; charset=utf-8";
        response.Cache.SetCacheability(HttpCacheability.Public);
        response.Cache.SetMaxAge(TimeSpan.FromMinutes(5)); // 快取 5 分鐘
        response.BufferOutput = false; // 關閉緩衝,直接串流輸出

        // 2. 取得動態內容 (此處示範字串,實際可從資料庫/快取/運算取得)
        string htmlContent = GetDynamicHtml(request.QueryString["id"]);

        // 3. 字串轉位元組陣列 (UTF-8 編碼)
        byte[] htmlBytes = System.Text.Encoding.UTF8.GetBytes(htmlContent);

        // 4. 建立記憶體流並分塊寫入輸出流 (模擬大內容串流)
        using (MemoryStream ms = new MemoryStream(htmlBytes))
        {
            const int BufferSize = 16 * 1024; // 16KB 緩衝區
            byte[] buffer = new byte[BufferSize];
            int bytesRead;
            while ((bytesRead = ms.Read(buffer, 0, BufferSize)) > 0)
            {
                response.OutputStream.Write(buffer, 0, bytesRead);
                response.Flush(); // 立即發送給客戶端 (長連線/大內容有效)
            }
        }
    }

    private string GetDynamicHtml(string id)
    {
        // 模擬從資料庫查詢
        if (string.IsNullOrEmpty(id)) id = "default";
        return $@"<!DOCTYPE html>
<html><head><meta charset='utf-8'/><title>動態內容 - {id}</title></head>
<body><h1>成功: 動態生成 HTML</h1><p>ID: {id}</p><p>時間: {DateTime.Now}</p></body></html>";
    }
}

前端頁面嵌入

<iframe src="HtmlHandler.ashx?id=12345" width="100%" height="400" frameborder="0"></iframe>
<!-- 或 AJAX 載入 -->
<div id="dynamicContent"></div>
<script>
    $.get("HtmlHandler.ashx?id=12345", function(html) {
        $("#dynamicContent").html(html);
    });
</script>

IHttpHandler 核心介面與生命週期

成員說明
IsReusable回傳 true 表示處理常式無狀態,可跨請求重用實例 (效能佳);false 表示每請求新建實例 (含狀態時)。
ProcessRequest(HttpContext)核心進入點,在此實作所有邏輯:讀取 Request、設定 Response 標頭、生成內容、寫入 OutputStream。

進階:通用泛型 Handler 基類

public abstract class StreamHandlerBase : IHttpHandler
{
    public bool IsReusable => true;
    
    public void ProcessRequest(HttpContext context)
    {
        try
        {
            PrepareResponse(context.Response);
            using (var stream = GenerateContentStream(context.Request))
            {
                if (stream == null) 
                {
                    WriteError(context.Response, "Content generation failed");
                    return;
                }
                StreamToResponse(stream, context.Response);
            }
        }
        catch (Exception ex)
        {
            WriteError(context.Response, "Server error: " + ex.Message);
        }
    }
    
    protected virtual void PrepareResponse(HttpResponse response)
    {
        response.BufferOutput = false;
        response.Cache.SetCacheability(HttpCacheability.NoCache); // 預設不快取
    }
    
    protected abstract Stream GenerateContentStream(HttpRequest request);
    
    private void StreamToResponse(Stream source, HttpResponse response)
    {
        const int BufferSize = 32 * 1024;
        byte[] buffer = new byte[BufferSize];
        int read;
        while ((read = source.Read(buffer, 0, BufferSize)) > 0)
        {
            response.OutputStream.Write(buffer, 0, read);
        }
    }
    
    private void WriteError(HttpResponse response, string msg)
    {
        response.StatusCode = 500;
        response.ContentType = "text/plain; charset=utf-8";
        byte[] err = System.Text.Encoding.UTF8.GetBytes(msg);
        response.OutputStream.Write(err, 0, err.Length);
    }
}

// 具體實作
public class ReportHandler : StreamHandlerBase
{
    protected override Stream GenerateContentStream(HttpRequest request)
    {
        string reportId = request.QueryString["id"];
        // 從資料庫/服務取得報表 HTML 字串
        string html = ReportService.GetReportHtml(reportId);
        return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html));
    }
}

效能優化關鍵點

  • BufferOutput = false:關閉 ASP.NET 內部緩衝,直接寫入網路串流,降低記憶體峰值、減少首位元組時間 (TTFB)。
  • 分塊傳輸:大內容分塊 Flush(),瀏覽器可漸進式渲染,體驗更佳。
  • 快取策略:靜態化內容設 SetMaxAge、SetETag;動態內容設 NoCache 或短期快取。
  • 壓縮:IIS 動態壓縮模組自動處理 text/html Gzip/Deflate,無需手動壓縮。
  • 非同步 I/O:.NET 4.5+ 可實作 IHttpAsyncHandler 或使用 HttpTaskAsyncHandler 釋放執行緒等待 DB/外部 API。

ashx vs aspx vs Web API 比較

特性.ashx (IHttpHandler).aspx (Page)Web API / MVC Controller
生命週期極簡 (單一方法)完整 Page 生命週期Controller/Action 流程
ViewState無有無
適用場景串流輸出、圖片動態生成、檔案下載、RSS/Atom、Webhook 接收完整頁面、表單、ViewState 需求REST API、JSON/XML、SPA 後端
效能開銷最低最高中等
路由支援需手動對應 / UrlRoutingModule內建內建屬性路由

結語

IHttpHandler (.ashx) 是 ASP.NET 輕量級輸出動態內容的最佳選擇:無 ViewState、無完整頁面生命週期、直接串流輸出、效能極佳。掌握 BufferOutput=false、分塊寫入、快取標頭、非同步擴展,即能構建高效能的動態 HTML、圖片、報表、檔案下載等串流端點。現代專案中,純 API 建議改用 ASP.NET Core Minimal API / Controller,但 .ashx 於舊系統維護、特定串流場景仍具不可替代價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved