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

Apache 模組開發實戰:從內容生成器到輸出過濾器

     編輯:關於C語言

前言

Apache HTTP Server 採模組化架構,核心功能皆以模組形式提供。開發自訂模組可擴充伺服器能力,例如自定義路由處理、請求/回應攔截、認證授權等。本文透過兩個完整範例,示範內容生成器與輸出過濾器的開發流程。

環境準備:安裝 apxs

apxs (APache eXtenSion tool) 是編譯、安裝 DSO (Dynamic Shared Object) 模組的標準工具。

# CentOS/RHEL
yum install -y httpd-devel

# Ubuntu/Debian
apt-get install -y apache2-dev

# 驗證
apxs -q CC      # 顯示編譯器
apxs -q CFLAGS  # 顯示編譯旗標

範例一:Hello World 內容生成器

1. 產生骨架

apxs -g -n helloworld

產生 mod_helloworld.c、Makefile 等檔案。

2. 核心處理函數

static int helloworld_handler(request_rec *r) {
    if (strcmp(r->handler, "helloworld")) return DECLINED; // 非本模組處理

    r->content_type = "text/html";
    if (!r->header_only)
        ap_rputs("The sample page from mod_helloworld.c\n", r);
    return OK;
}

3. 掛鉤註冊

static void helloworld_register_hooks(apr_pool_t *p) {
    ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
    STANDARD20_MODULE_STUFF,
    NULL, NULL, NULL, NULL, NULL,
    helloworld_register_hooks
};

4. 編譯、安裝、配置

apxs -c mod_helloworld.c      # 編譯產生 .so
apxs -i mod_helloworld.la     # 安裝到 modules/ 目錄

修改 httpd.conf:

LoadModule helloworld_module modules/mod_helloworld.so
<Location /helloworld>
    SetHandler helloworld
</Location>

重啟 Apache:apachectl restart。瀏覽 https://localhost/helloworld 即可看到輸出。

範例二:大寫轉換輸出過濾器

過濾器位於「內容生成器」與「網路輸出」之間,可攔截、修改回應內容。適用於壓縮、加密、關鍵字替換等場景。

核心過濾函數

static apr_status_t CaseFilterOutFilter(ap_filter_t *f, apr_bucket_brigade *pbbIn) {
    request_rec *r = f->r;
    conn_rec *c = r->connection;
    apr_bucket_brigade *pbbOut = apr_brigade_create(r->pool, c->bucket_alloc);

    for (apr_bucket *bkt = APR_BRIGADE_FIRST(pbbIn);
         bkt != APR_BRIGADE_SENTINEL(pbbIn);
         bkt = APR_BUCKET_NEXT(bkt)) {

        if (APR_BUCKET_IS_EOS(bkt)) { // 串流結束
            APR_BRIGADE_INSERT_TAIL(pbbOut, apr_bucket_eos_create(c->bucket_alloc));
            continue;
        }

        const char *data; apr_size_t len;
        apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);

        char *buf = apr_bucket_alloc(len, c->bucket_alloc);
        for (apr_size_t i = 0; i < len; ++i) buf[i] = apr_toupper(data[i]);

        apr_bucket *out = apr_bucket_heap_create(buf, len, apr_bucket_free, c->bucket_alloc);
        APR_BRIGADE_INSERT_TAIL(pbbOut, out);
    }

    apr_brigade_cleanup(pbbIn);
    return ap_pass_brigade(f->next, pbbOut); // 傳遞給下一個過濾器
}

模組掛鉤與配置指令

static void CaseFilterInsertFilter(request_rec *r) {
    CaseFilterConfig *cfg = ap_get_module_config(r->server->module_config, &case_filter_module);
    if (cfg->bEnabled)
        ap_add_output_filter("CaseFilter", NULL, r, r->connection);
}

static const command_rec CaseFilterCmds[] = {
    AP_INIT_FLAG("CaseFilter", CaseFilterEnable, NULL, RSRC_CONF, "Enable case filter"),
    { NULL }
};

static void CaseFilterRegisterHooks(apr_pool_t *p) {
    ap_hook_insert_filter(CaseFilterInsertFilter, NULL, NULL, APR_HOOK_MIDDLE);
    ap_register_output_filter("CaseFilter", CaseFilterOutFilter, NULL, AP_FTYPE_RESOURCE);
}

啟用配置

LoadModule case_filter_module modules/mod_casefilter.so
CaseFilter On

關鍵概念總結

概念說明
Handler (內容生成器)產生回應主體,掛在 ap_hook_handler
Output Filter (輸出過濾器)處理回應串流,掛在 ap_hook_insert_filter + ap_register_output_filter
Bucket BrigadeApache 的串流資料結構,由多個 bucket 串連
apr_pool_t記憶體池,自動生命週期管理,避免洩漏

常見坑點提醒

  • DSO 模組必須在 httpd.conf 中 LoadModule,且路徑正確
  • 過濾器務必正確處理 EOS (End Of Stream) bucket,否則連線會掛住
  • 使用 apr_pcalloc、apr_bucket_alloc 等 APR 函數分配記憶體,隨 pool 自動釋放
  • 開發期啟用 LogLevel debug 觀察模組載入與掛鉤順序
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved