自定义Apache C模块能否按Directory指令配置不同host/port参数?
问题原因
你当前是用全局变量存储apiHost和apiPort的值,Apache加载配置时会按顺序执行所有配置指令,后面的<Directory>块会直接覆盖前面的变量值,导致所有请求最终都使用最后一组配置参数。
解决方案
要实现不同目录使用独立配置,需要为每个目录块创建专属的配置结构体,让Apache为每个<Directory>维护独立的配置实例,具体步骤如下:
1. 定义目录配置结构体
创建一个结构体来存储每个目录的专属配置:
#include <httpd.h> #include <http_config.h> // 存储每个目录的API转发配置 typedef struct { const char *api_host; int api_port; } MineDirConfig;
2. 实现配置结构体的创建与合并函数
- 创建函数:每个新的
<Directory>块会调用此函数生成独立的配置实例
// 创建新的目录配置实例 static void *mine_create_dir_config(apr_pool_t *pool, char *dir) { MineDirConfig *cfg = apr_pcalloc(pool, sizeof(MineDirConfig)); // 设置默认值(可根据需求调整) cfg->api_host = NULL; cfg->api_port = 0; return cfg; }
- 合并函数:处理配置继承逻辑(比如子目录继承父目录配置),优先使用当前目录的配置
// 合并父目录与当前目录的配置 static void *mine_merge_dir_config(apr_pool_t *pool, void *base, void *new) { MineDirConfig *merged = apr_pcalloc(pool, sizeof(MineDirConfig)); MineDirConfig *base_cfg = (MineDirConfig *)base; MineDirConfig *new_cfg = (MineDirConfig *)new; // 当前目录有配置则用当前的,否则继承父目录 merged->api_host = new_cfg->api_host ? new_cfg->api_host : base_cfg->api_host; merged->api_port = new_cfg->api_port != 0 ? new_cfg->api_port : base_cfg->api_port; return merged; }
3. 修改配置指令的处理逻辑
将配置值存入当前目录的配置结构体,而非全局变量:
// 处理apiHost配置指令 static const char *mine_set_api_host(cmd_parms *parms, void *mconfig, const char *arg) { MineDirConfig *cfg = (MineDirConfig *)mconfig; // 用Apache内存池托管字符串,避免内存泄漏 cfg->api_host = apr_pstrdup(parms->pool, arg); return NULL; } // 处理apiPort配置指令(增加合法性校验) static const char *mine_set_api_port(cmd_parms *parms, void *mconfig, const char *arg) { MineDirConfig *cfg = (MineDirConfig *)mconfig; int port = atoi(arg); if (port <= 0 || port > 65535) { return "apiPort must be between 1 and 65535"; } cfg->api_port = port; return NULL; } // 注册配置指令 static const command_rec mine_cmds[] = { AP_INIT_TAKE1("apiHost", (cmd_func)mine_set_api_host, NULL, OR_AUTHCFG, "API backend host"), AP_INIT_TAKE1("apiPort", (cmd_func)mine_set_api_port, NULL, OR_AUTHCFG, "API backend port"), { NULL } // 指令数组结束标记 };
4. 注册配置结构体到模块
在模块定义中关联配置创建与合并函数,让Apache识别目录级配置:
// 请求处理函数(示例) static int mine_handler(request_rec *r) { // 获取当前请求对应的目录配置 MineDirConfig *cfg = ap_get_module_config(r->per_dir_config, &mine_module); // 校验配置是否存在 if (!cfg->api_host || cfg->api_port == 0) { ap_rprintf(r, "API host/port not configured for this directory"); return HTTP_INTERNAL_SERVER_ERROR; } // 后续转发逻辑使用cfg->api_host和cfg->api_port // ... return OK; } // 注册钩子(示例) static void mine_register_hooks(apr_pool_t *pool) { ap_hook_handler(mine_handler, NULL, NULL, APR_HOOK_MIDDLE); } // 模块定义 module AP_MODULE_DECLARE_DATA mine_module = { STANDARD20_MODULE_STUFF, mine_create_dir_config, // 目录配置创建函数 mine_merge_dir_config, // 目录配置合并函数 NULL, // 服务器级配置创建(无需则设为NULL) NULL, // 服务器级配置合并(无需则设为NULL) mine_cmds, // 配置指令数组 mine_register_hooks // 钩子注册函数 };
5. 重新编译部署模块
修改代码后重新编译生成.so文件,替换原有模块并重启Apache,此时不同<Directory>的配置会独立生效。
内容的提问来源于stack exchange,提问作者user61526
相关产品推荐
相关产品推荐

