You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:00:19