ngx_http_destination_charset

📅 2026/7/8 20:31:45
ngx_http_destination_charset
1 定义ngx_http_destination_charset 函数 定义在 src/http/modules/ngx_http_charset_filter_module.cstaticngx_int_tngx_http_destination_charset(ngx_http_request_t*r,ngx_str_t*name){ngx_int_tcharset;ngx_http_charset_t*charsets;ngx_http_variable_value_t*vv;ngx_http_charset_loc_conf_t*mlcf;ngx_http_charset_main_conf_t*mcf;if(r-headers_out.content_type.len0){returnNGX_DECLINED;}if(r-headers_out.override_charsetr-headers_out.override_charset-len){*name*r-headers_out.override_charset;charsetngx_http_get_charset(r,name);if(charset!NGX_HTTP_NO_CHARSET){returncharset;}ngx_log_error(NGX_LOG_ERR,r-connection-log,0,unknown charset \%V\ to override,name);returnNGX_DECLINED;}mlcfngx_http_get_module_loc_conf(r,ngx_http_charset_filter_module);charsetmlcf-charset;if(charsetNGX_HTTP_CHARSET_OFF){returnNGX_DECLINED;}if(r-headers_out.charset.len){if(mlcf-override_charset0){returnNGX_DECLINED;}}else{if(ngx_http_test_content_type(r,mlcf-types)NULL){returnNGX_DECLINED;}}if(charsetNGX_HTTP_CHARSET_VAR){mcfngx_http_get_module_main_conf(r,ngx_http_charset_filter_module);charsetsmcf-charsets.elts;*namecharsets[charset].name;returncharset;}vvngx_http_get_indexed_variable(r,charset-NGX_HTTP_CHARSET_VAR);if(vvNULL||vv-not_found){returnNGX_ERROR;}name-lenvv-len;name-datavv-data;returnngx_http_get_charset(r,name);}2 目的ngx_http_destination_charset函数是 Nginx 字符集处理流程中的一个关键辅助函数。它的核心任务只有一个明确地计算出当前响应最终应该使用哪个字符集。这个字符集会成为后续所有处理如设置Content-Type头、决定是否进行内容转换的目标依据。它并不是简单地读取配置文件里的charset指令而是依据一套严格的优先级顺序来决定最终值最终这个函数会返回目标字符集在内部数组中的索引并通过指针参数name返回字符集的名称字符串。为什么需要设计这样一个函数分离 核心流程和配置细节使代码逻辑更加清晰。封装复杂的“条件性生效”判断如果没有这个函数这些“在特定条件下不生效”的逻辑会散落在主流程的各处容易造成逻辑遗漏。提供统一的校验与错误处理入口设计这样一个独立的函数实现了优先级调度的清晰化、生效条件的集中管理、外部输入的严格校验以及请求类型的职责分离使得 Nginx 的字符集处理机制既灵活又健壮。3 详解1 函数签名staticngx_int_tngx_http_destination_charset(ngx_http_request_t*r,ngx_str_t*name)1. 返回值类型ngx_int_t用于表示函数的执行结果或状态。该函数不返回字符集本身而是返回一个整数其含义根据上下文有不同的解释字符集索引非负整数当成功确定了目标字符集时返回值是该字符集在全局字符集数组中的索引同时通过name参数输出字符集的名称字符串。NGX_HTTP_NO_CHARSET表示配置中明确要求不设置任何字符集charset off。NGX_DECLINED表示当前不需要或不应该设置字符集。例如响应没有Content-Type或者配置不允许覆盖已存在的字符集或者 MIME 类型不在允许的列表中。NGX_ERROR表示发生错误例如变量解析失败或指定的字符集名称不在已知列表中。调用者通过检查返回值来决定后续操作是否设置字符集、是否跳过处理、是否报错。2. 函数名ngx_http_destination_charset函数名由下划线分隔的多个部分组成遵循 Nginx 的命名惯例destination意为“目标”明确指代当前响应的目标字符集即最终要设置到Content-Type头中的字符集。charset直接对应“字符集”概念指 HTTP 中的charset参数例如utf-8、gbk。因此ngx_http_destination_charset的完整含义是在 HTTP 模块中确定响应最终应使用的目标字符集的函数。它与ngx_http_source_charset确定源字符集相对应两者配合完成字符集转换的决策。3. 参数列表(ngx_http_request_t *r, ngx_str_t *name)函数接收两个参数提供计算所需的全部信息。3.1 第一个参数ngx_http_request_t *r指向 HTTP 请求结构体的指针。3.2 第二个参数ngx_str_t *name作用这是一个输出参数。函数在成功确定目标字符集后会将字符集的名称字符串例如utf-8的地址和长度写入name指向的结构体供调用者后续使用为何使用指针传递C 语言函数通常通过指针参数来返回额外的结果。这样可以避免复制整个字符串而只需修改指针指向的内容2 逻辑流程1 无 Content-Type 则退出。 2 若有强制字符集 (override_charset)优先使用并校验 合法则返回否则记录错误后退出。 3 获取配置的 charset 值若为 OFF 则退出。 4 检查是否应该覆盖已有的 charset 或响应的媒体类型是否在允许列表中决定是否继续。 5 若配置值是静态索引直接返回其索引和名称。 6 若配置值是变量解析变量值校验后返回对应索引。{ngx_int_tcharset;ngx_http_charset_t*charsets;ngx_http_variable_value_t*vv;ngx_http_charset_loc_conf_t*mlcf;ngx_http_charset_main_conf_t*mcf;局部变量声明1 无 Content-Typeif(r-headers_out.content_type.len0){returnNGX_DECLINED;}如果 Content-Type 不存在则跳过没有 Content-Type就不可能也不应该设置 charset 参数。因此函数直接返回 NGX_DECLINED表示“不处理”。2 若有强制字符集优先使用if(r-headers_out.override_charsetr-headers_out.override_charset-len){*name*r-headers_out.override_charset;charsetngx_http_get_charset(r,name);if(charset!NGX_HTTP_NO_CHARSET){returncharset;}ngx_log_error(NGX_LOG_ERR,r-connection-log,0,unknown charset \%V\ to override,name);returnNGX_DECLINED;}处理override_charset强制字符集r-headers_out.override_charset是一个指针当某个内容模块如代理模块想要强制使用特定字符集时会设置这个字段。如果该指针非 NULL 且其 len长度大于 0则表示存在有效的强制字符集名称。*name *r-headers_out.override_charset;将强制字符集的字符串直接复制给输出参数namengx_http_get_charset(r, name)在全局字符集列表中查找该名称返回对应的字符集索引。如果找到了charset ! NGX_HTTP_NO_CHARSET直接返回该索引。如果找不到记录一条错误日志未知的字符集名称然后返回 NGX_DECLINED 表示放弃处理。设计意义强制字符集拥有最高优先级。这里先检查它如果存在且合法就立即返回不合法则记录错误并优雅降级避免整个请求失败。3 获取配置mlcfngx_http_get_module_loc_conf(r,ngx_http_charset_filter_module);charsetmlcf-charset;if(charsetNGX_HTTP_CHARSET_OFF){returnNGX_DECLINED;}获取 location 配置及 charset 指令值ngx_http_get_module_loc_conf获取当前location合并后的字符集模块配置。mlcf-charset是charset指令配置的值可能是一个字符集索引也可能是特殊值NGX_HTTP_CHARSET_OFF表示charset off;即明确不处理字符集。如果为OFF直接返回NGX_DECLINED不做任何处理。4 检查配置if(r-headers_out.charset.len){if(mlcf-override_charset0){returnNGX_DECLINED;}}else{if(ngx_http_test_content_type(r,mlcf-types)NULL){returnNGX_DECLINED;}}检查是否应该覆盖或跳过检查响应头中是否已经存在charset参数如果已经有charsetmlcf-override_charset是override_charset指令的值。若为 0表示配置没有启用强制覆盖。此时为了保护上游设置直接返回NGX_DECLINED不再覆盖已有的字符集。如果还没有 charset调用ngx_http_test_content_type(r, mlcf-types)检查当前响应的Content-Type类型如 text/html是否在charset_types指令允许的列表内。如果不在允许列表中函数返回NGX_DECLINED表示不应该为该类型添加charset设计意义这两层检查确保字符集设置只在真正需要时进行——既不随意覆盖上游设定也不为不合适的 MIME 类型添加 charset。5 处理静态字符集if(charsetNGX_HTTP_CHARSET_VAR){mcfngx_http_get_module_main_conf(r,ngx_http_charset_filter_module);charsetsmcf-charsets.elts;*namecharsets[charset].name;returncharset;}处理静态字符集非变量charset现在是mlcf-charset的值。如果它的值小于NGX_HTTP_CHARSET_VAR说明它是一个预先定义的静态字符集索引配置解析时已经确定。获取主配置中的字符集数组charsets通过索引找到对应的字符集结构体将其name字段赋值给输出参数*name直接返回该索引。6 处理动态字符集vvngx_http_get_indexed_variable(r,charset-NGX_HTTP_CHARSET_VAR);if(vvNULL||vv-not_found){returnNGX_ERROR;}name-lenvv-len;name-datavv-data;returnngx_http_get_charset(r,name);}处理动态字符集来自变量如果charset NGX_HTTP_CHARSET_VAR说明它是一个变量索引配置中写的是 charset $var。charset - NGX_HTTP_CHARSET_VAR计算出变量在系统中的编号。ngx_http_get_indexed_variable获取该变量的当前值。返回值vv指向变量值结构体。如果vv NULL 或 vv-not_found为真表示变量未定义或没有值此时无法确定字符集返回NGX_ERROR如果变量有值将它的data 和 len 赋给 name使之指向实际的字符集名称字符串。最后调用ngx_http_get_charset(r, name)在全局字符集列表中查找该名称返回对应的索引如果找不到会返回NGX_HTTP_NO_CHARSET。设计意义字符集可以动态地由 Nginx 变量决定。这段代码负责解析变量值并验证它是否是一个已知的字符集。