Apache 模块开发 #

模块开发概述 #

Apache 模块架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Apache 模块架构                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Apache 核心                                                │
│  ├── HTTP 协议处理                                          │
│  ├── 连接管理                                               │
│  ├── 配置解析                                               │
│  └── 内存池管理                                             │
│                                                             │
│  模块系统                                                   │
│  ├── 钩子机制(Hook)                                       │
│  ├── 过滤器链(Filter)                                     │
│  ├── 内容处理器(Handler)                                  │
│  └── 配置指令(Directive)                                  │
│                                                             │
│  模块类型                                                   │
│  ├── 内容生成模块                                           │
│  ├── 认证授权模块                                           │
│  ├── 过滤器模块                                             │
│  └── 日志模块                                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

请求处理流程 #

text
┌─────────────────────────────────────────────────────────────┐
│                    请求处理流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 连接阶段                                                │
│     create_connection                                       │
│     └── 建立连接                                           │
│                                                             │
│  2. 请求解析阶段                                            │
│     pre_read_request                                        │
│     read_request                                            │
│     post_read_request                                       │
│     └── 解析 HTTP 请求                                     │
│                                                             │
│  3. URL 转换阶段                                            │
│     translate_name                                          │
│     map_to_storage                                          │
│     └── URL 到文件路径转换                                 │
│                                                             │
│  4. 认证授权阶段                                            │
│     check_user_id                                           │
│     auth_checker                                            │
│     access_checker                                          │
│     └── 用户认证和授权                                     │
│                                                             │
│  5. 内容类型阶段                                            │
│     type_checker                                            │
│     fixups                                                  │
│     └── 确定内容类型                                       │
│                                                             │
│  6. 内容生成阶段                                            │
│     handler                                                 │
│     └── 生成响应内容                                       │
│                                                             │
│  7. 日志阶段                                                │
│     logging                                                 │
│     └── 记录访问日志                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

开发环境准备 #

安装开发工具 #

bash
# Ubuntu/Debian
sudo apt install apache2-dev build-essential

# CentOS/RHEL
sudo yum install httpd-devel gcc make

# 安装 APR 开发库
sudo apt install libapr1-dev libaprutil1-dev

开发目录结构 #

text
mod_example/
├── mod_example.c      # 模块源代码
├── config.m4          # 构建配置
├── Makefile           # 编译规则
└── README.md          # 文档

简单模块示例 #

Hello World 模块 #

c
/* mod_hello.c - 简单的 Hello World 模块 */

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

/* 内容处理器函数 */
static int hello_handler(request_rec *r)
{
    /* 检查请求方法 */
    if (strcmp(r->handler, "hello")) {
        return DECLINED;
    }
    
    /* 设置内容类型 */
    r->content_type = "text/html";
    
    /* 输出内容 */
    ap_rputs("<html><body>", r);
    ap_rputs("<h1>Hello, Apache Module!</h1>", r);
    ap_rputs("</body></html>", r);
    
    return OK;
}

/* 注册钩子 */
static void hello_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(hello_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* 模块定义 */
module AP_MODULE_DECLARE_DATA hello_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                  /* 创建目录配置 */
    NULL,                  /* 合并目录配置 */
    NULL,                  /* 创建服务器配置 */
    NULL,                  /* 合并服务器配置 */
    NULL,                  /* 配置指令表 */
    hello_register_hooks   /* 注册钩子 */
};

编译模块 #

bash
# 使用 apxs 编译
apxs -c mod_hello.c

# 安装模块
sudo apxs -i -a mod_hello.la

# 或使用 Makefile
# Makefile 内容
APXS = apxs
all: mod_hello.la
mod_hello.la: mod_hello.c
    $(APXS) -c mod_hello.c
install: mod_hello.la
    $(APXS) -i -a mod_hello.la

配置使用模块 #

apache
# 加载模块
LoadModule hello_module modules/mod_hello.so

# 配置处理器
<Location /hello>
    SetHandler hello
</Location>

钩子函数详解 #

常用钩子 #

c
/* ============================================
 * 常用钩子函数
 * ============================================ */

/* 1. 内容处理器钩子 */
static int my_handler(request_rec *r)
{
    /* 处理请求并生成响应 */
    return OK;  /* 或 DECLINED, HTTP_OK, HTTP_NOT_FOUND 等 */
}

/* 2. 访问检查钩子 */
static int my_access_checker(request_rec *r)
{
    /* 检查访问权限 */
    if (/* 允许访问 */) {
        return OK;
    }
    return HTTP_FORBIDDEN;
}

/* 3. 认证钩子 */
static int my_check_user_id(request_rec *r)
{
    /* 验证用户身份 */
    return OK;
}

/* 4. 授权钩子 */
static int my_auth_checker(request_rec *r)
{
    /* 检查用户权限 */
    return OK;
}

/* 5. URL 转换钩子 */
static int my_translate_name(request_rec *r)
{
    /* 转换 URL */
    return OK;
}

/* 6. 日志钩子 */
static int my_logger(request_rec *r)
{
    /* 记录日志 */
    return OK;
}

/* 7. 后置读取请求钩子 */
static int my_post_read_request(request_rec *r)
{
    /* 请求读取后的处理 */
    return OK;
}

注册钩子 #

c
static void my_register_hooks(apr_pool_t *p)
{
    /* 注册处理器钩子 */
    ap_hook_handler(my_handler, NULL, NULL, APR_HOOK_MIDDLE);
    
    /* 注册访问检查钩子 */
    ap_hook_access_checker(my_access_checker, NULL, NULL, APR_HOOK_MIDDLE);
    
    /* 注册认证钩子 */
    ap_hook_check_user_id(my_check_user_id, NULL, NULL, APR_HOOK_MIDDLE);
    
    /* 注册授权钩子 */
    ap_hook_auth_checker(my_auth_checker, NULL, NULL, APR_HOOK_MIDDLE);
    
    /* 注册 URL 转换钩子 */
    ap_hook_translate_name(my_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
    
    /* 注册日志钩子 */
    ap_hook_log_transaction(my_logger, NULL, NULL, APR_HOOK_MIDDLE);
    
    /* 注册后置读取请求钩子 */
    ap_hook_post_read_request(my_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
}

配置指令 #

定义配置指令 #

c
/* ============================================
 * 配置指令定义
 * ============================================ */

/* 模块配置结构 */
typedef struct {
    const char *message;
    int enabled;
} hello_config;

/* 创建目录配置 */
static void *hello_create_dir_config(apr_pool_t *p, char *dir)
{
    hello_config *cfg = apr_pcalloc(p, sizeof(hello_config));
    cfg->message = "Hello, World!";
    cfg->enabled = 0;
    return cfg;
}

/* HelloMessage 指令处理函数 */
static const char *set_hello_message(cmd_parms *cmd, void *mconfig, const char *arg)
{
    hello_config *cfg = (hello_config *)mconfig;
    cfg->message = arg;
    return NULL;
}

/* HelloEnabled 指令处理函数 */
static const char *set_hello_enabled(cmd_parms *cmd, void *mconfig, int arg)
{
    hello_config *cfg = (hello_config *)mconfig;
    cfg->enabled = arg;
    return NULL;
}

/* 配置指令表 */
static const command_rec hello_commands[] = {
    AP_INIT_TAKE1("HelloMessage", set_hello_message, NULL, OR_ALL,
                  "Set the hello message"),
    AP_INIT_FLAG("HelloEnabled", set_hello_enabled, NULL, OR_ALL,
                 "Enable or disable the hello module"),
    {NULL}
};

使用配置 #

apache
# 在配置文件中使用
<Location /hello>
    SetHandler hello
    HelloMessage "Welcome to my site!"
    HelloEnabled On
</Location>

请求对象 #

request_rec 结构 #

c
/* ============================================
 * request_rec 常用成员
 * ============================================ */

/* 请求信息 */
r->method;           /* 请求方法:GET, POST 等 */
r->uri;              /* 请求 URI */
r->filename;         /* 文件路径 */
r->args;             /* 查询字符串 */
r->protocol;         /* 协议版本 */
r->hostname;         /* 主机名 */
r->handler;          /* 处理器名称 */

/* 请求头 */
r->headers_in;       /* 请求头表 */
r->headers_out;      /* 响应头表 */
r->err_headers_out;  /* 错误响应头表 */

/* 连接信息 */
r->connection;       /* 连接对象 */
r->server;           /* 服务器对象 */
r->user;             /* 认证用户名 */
r->ap_auth_type;     /* 认证类型 */

/* 内容信息 */
r->content_type;     /* 内容类型 */
r->content_encoding; /* 内容编码 */
r->content_languages; /* 内容语言 */

/* 状态 */
r->status;           /* 响应状态码 */
r->status_line;      /* 状态行 */

读取请求头 #

c
/* 获取请求头 */
const char *user_agent = apr_table_get(r->headers_in, "User-Agent");
const char *referer = apr_table_get(r->headers_in, "Referer");
const char *host = apr_table_get(r->headers_in, "Host");

设置响应头 #

c
/* 设置响应头 */
apr_table_set(r->headers_out, "X-Custom-Header", "value");
apr_table_set(r->headers_out, "Cache-Control", "no-cache");

/* 设置内容类型 */
r->content_type = "application/json";

输出响应内容 #

c
/* 输出字符串 */
ap_rputs("Hello, World!", r);

/* 输出格式化字符串 */
ap_rprintf(r, "Request URI: %s\n", r->uri);

/* 输出数据 */
ap_rwrite(data, len, r);

/* 刷新输出 */
ap_rflush(r);

内存管理 #

内存池 #

c
/* ============================================
 * APR 内存池
 * ============================================ */

/* 从内存池分配内存 */
void *ptr = apr_palloc(r->pool, size);
void *ptr = apr_pcalloc(r->pool, size);  /* 初始化为 0 */

/* 字符串操作 */
char *str = apr_pstrdup(r->pool, "hello");
char *str = apr_pstrcat(r->pool, "hello", " ", "world", NULL);
char *str = apr_psprintf(r->pool, "Value: %d", value);

过滤器 #

输出过滤器 #

c
/* 输出过滤器函数 */
static apr_status_t my_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
    apr_bucket *b;
    
    for (b = APR_BRIGADE_FIRST(bb);
         b != APR_BRIGADE_SENTINEL(bb);
         b = APR_BUCKET_NEXT(b))
    {
        /* 处理每个 bucket */
        if (!APR_BUCKET_IS_EOS(b)) {
            const char *data;
            apr_size_t len;
            apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
            /* 处理数据 */
        }
    }
    
    return ap_pass_brigade(f->next, bb);
}

/* 注册过滤器 */
static void my_register_hooks(apr_pool_t *p)
{
    ap_register_output_filter("MY_FILTER", my_output_filter,
                              NULL, AP_FTYPE_RESOURCE);
}

完整模块示例 #

c
/* mod_counter.c - 访问计数器模块 */

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "apr_atomic.h"

/* 模块配置 */
typedef struct {
    const char *header_name;
} counter_config;

/* 计数器 */
static volatile apr_uint32_t counter = 0;

/* 创建配置 */
static void *counter_create_dir_config(apr_pool_t *p, char *dir)
{
    counter_config *cfg = apr_pcalloc(p, sizeof(counter_config));
    cfg->header_name = "X-Request-Count";
    return cfg;
}

/* 设置头名称指令 */
static const char *set_header_name(cmd_parms *cmd, void *mconfig, const char *arg)
{
    counter_config *cfg = (counter_config *)mconfig;
    cfg->header_name = arg;
    return NULL;
}

/* 配置指令表 */
static const command_rec counter_commands[] = {
    AP_INIT_TAKE1("CounterHeaderName", set_header_name, NULL, OR_ALL,
                  "Set the counter header name"),
    {NULL}
};

/* 后置读取请求钩子 */
static int counter_post_read_request(request_rec *r)
{
    counter_config *cfg = ap_get_module_config(r->per_dir_config, &counter_module);
    
    /* 增加计数器 */
    apr_uint32_t count = apr_atomic_inc32(&counter) + 1;
    
    /* 设置响应头 */
    char count_str[32];
    snprintf(count_str, sizeof(count_str), "%u", count);
    apr_table_set(r->headers_out, cfg->header_name, count_str);
    
    return OK;
}

/* 注册钩子 */
static void counter_register_hooks(apr_pool_t *p)
{
    ap_hook_post_read_request(counter_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
}

/* 模块定义 */
module AP_MODULE_DECLARE_DATA counter_module = {
    STANDARD20_MODULE_STUFF,
    counter_create_dir_config,  /* 创建目录配置 */
    NULL,                       /* 合并目录配置 */
    NULL,                       /* 创建服务器配置 */
    NULL,                       /* 合并服务器配置 */
    counter_commands,           /* 配置指令表 */
    counter_register_hooks      /* 注册钩子 */
};

调试技巧 #

日志输出 #

c
/* 使用 ap_log_error 记录日志 */
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Error message");
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Info: %s", value);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Debug: uri=%s", r->uri);

使用 gdb 调试 #

bash
# 调试 Apache
sudo gdb httpd

# 设置断点
(gdb) break my_handler
(gdb) run -X

下一步 #

模块开发是 Apache 的高级主题,建议继续学习 PHP 集成 了解实际应用集成!

最后更新:2026-03-29