插件窝 干货文章 nginx怎么使用ctx实现数据共享

nginx怎么使用ctx实现数据共享

ctx module ngx NULL 769    来源:    2025-04-25

在Nginx中使用ctx实现数据共享

Nginx中的ctx(context)是一种在不同处理阶段之间共享数据的机制。下面我将详细介绍如何使用ctx实现数据共享。

基本概念

Nginx提供了几种上下文类型用于数据共享: 1. 请求级ctx (ngx_http_request_t中的ctx数组) - 只在单个请求生命周期内有效 2. 主配置ctx - 在配置重载时会被重置 3. 位置配置ctx - 特定location块内的数据共享

请求级ctx使用方式

1. 定义模块上下文结构

typedef struct {
    ngx_str_t shared_data;
    int       shared_value;
} my_module_ctx_t;

2. 获取或创建ctx

static my_module_ctx_t *get_my_module_ctx(ngx_http_request_t *r) {
    my_module_ctx_t *ctx = ngx_http_get_module_ctx(r, my_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(my_module_ctx_t));
        if (ctx == NULL) {
            return NULL;
        }

        ngx_http_set_ctx(r, ctx, my_module);
    }

    return ctx;
}

3. 在不同阶段使用共享数据

// 在某个处理阶段设置数据
static ngx_int_t my_handler(ngx_http_request_t *r) {
    my_module_ctx_t *ctx = get_my_module_ctx(r);
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ctx->shared_value = 42;
    ctx->shared_data = ngx_string("Hello from ctx");

    return NGX_OK;
}

// 在另一个处理阶段读取数据
static ngx_int_t my_other_handler(ngx_http_request_t *r) {
    my_module_ctx_t *ctx = ngx_http_get_module_ctx(r, my_module);
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 
                 "Shared value: %d, data: %V", 
                 ctx->shared_value, &ctx->shared_data);

    return NGX_OK;
}

配置级ctx使用方式

1. 定义主配置结构

typedef struct {
    ngx_str_t config_data;
    int       config_value;
} my_module_main_conf_t;

2. 在模块定义中声明

static ngx_http_module_t my_module_ctx = {
    NULL,                                  /* preconfiguration */
    NULL,                                  /* postconfiguration */

    ngx_http_my_module_create_main_conf,  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    NULL,                                  /* create location configuration */
    NULL                                   /* merge location configuration */
};

3. 创建主配置

static void *ngx_http_my_module_create_main_conf(ngx_conf_t *cf) {
    my_module_main_conf_t *conf;

    conf = ngx_pcalloc(cf->pool, sizeof(my_module_main_conf_t));
    if (conf == NULL) {
        return NULL;
    }

    // 初始化默认值
    conf->config_value = 100;
    conf->config_data = ngx_string("default");

    return conf;
}

4. 在处理器中访问配置

static ngx_int_t my_handler(ngx_http_request_t *r) {
    my_module_main_conf_t *mcf = ngx_http_get_module_main_conf(r, my_module);

    ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 
                 "Config value: %d, data: %V", 
                 mcf->config_value, &mcf->config_data);

    return NGX_OK;
}

注意事项

  1. 内存管理:请求级ctx使用的内存来自请求内存池(r->pool),会在请求结束时自动释放
  2. 并发安全:ctx是请求特定的,天然支持并发
  3. 模块索引:确保你的模块有唯一的ngx_module_t定义和正确的索引
  4. 性能考虑:ctx访问非常高效,适合频繁的数据共享

实际应用示例

假设我们要在Nginx中实现一个简单的请求计数器:

typedef struct {
    int request_count;
} my_counter_ctx_t;

static ngx_int_t my_counter_handler(ngx_http_request_t *r) {
    my_counter_ctx_t *ctx = ngx_http_get_module_ctx(r, my_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(my_counter_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }
        ngx_http_set_ctx(r, ctx, my_module);
        ctx->request_count = 0;
    }

    ctx->request_count++;

    ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 
                 "Request count: %d", ctx->request_count);

    return NGX_OK;
}

通过这种方式,你可以在Nginx的不同处理阶段高效地共享数据。