NGINX源码中按需要修改发送的流的Content-Type值

在做CDN的项目中, 由于媒体文件没有后缀, NGINX不会自动根据mime.types来自动获取Content-Type的值,之前使用默认的Content-Type: application/octet-stream;  有部分客户端不会自己去识别流的格式, 不指定正确的Content-Type值无法播放文件,所以我只有修改NGINX源码来指定要发送的Content-Type值了。

记录下我修改的东西,方便以后查阅。


ngx_int_t  ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_str_t *ct, ngx_http_complex_value_t *cv)
ngx_int_t  ngx_http_set_content_type(ngx_http_request_t *r)
r->uri 得到文件名, 查找   文件名.type


//GDB调试时得到的调用堆栈
Breakpoint 1, ngx_http_set_content_type (r=0x7e6760) at src/http/ngx_http_core_module.c:1750
1750        if (r->headers_out.content_type.len) {
(gdb) bt
#0  ngx_http_set_content_type (r=0x7e6760) at src/http/ngx_http_core_module.c:1750
#1  0x0000000000482704 in ngx_http_static_handler (r=0x7e6760) at src/http/modules/ngx_http_static_module.c:223
#2  0x00000000004546f1 in ngx_http_core_content_phase (r=0x7e6760, ph=0x80a3e8) at src/http/ngx_http_core_module.c:1414
#3  0x00000000004531d7 in ngx_http_core_run_phases (r=0x7e6760) at src/http/ngx_http_core_module.c:888
#4  0x000000000045314e in ngx_http_handler (r=0x7e6760) at src/http/ngx_http_core_module.c:871
#5  0x0000000000461604 in ngx_http_process_request (r=0x7e6760) at src/http/ngx_http_request.c:1694
#6  0x000000000046000f in ngx_http_process_request_headers (rev=0x80cef8) at src/http/ngx_http_request.c:1144
#7  0x000000000045f7c4 in ngx_http_process_request_line (rev=0x80cef8) at src/http/ngx_http_request.c:940
#8  0x000000000045e9ac in ngx_http_init_request (rev=0x80cef8) at src/http/ngx_http_request.c:524
#9  0x0000000000448d2a in ngx_epoll_process_events (cycle=0x7a1760, timer=60000, flags=1)
    at src/event/modules/ngx_epoll_module.c:683
#10 0x0000000000439738 in ngx_process_events_and_timers (cycle=0x7a1760) at src/event/ngx_event.c:247
#11 0x0000000000445916 in ngx_single_process_cycle (cycle=0x7a1760) at src/os/unix/ngx_process_cycle.c:316
#12 0x00000000004153e8 in main (argc=1, argv=0x7fffffffe548) at src/core/nginx.c:407



//修改下面这个函数即可
ngx_int_t
ngx_http_set_content_type(ngx_http_request_t *r)
{
    u_char                     c, *exten;
    ngx_str_t                 *type;
    ngx_uint_t                 i, hash;
    ngx_http_core_loc_conf_t  *clcf;

    if (r->headers_out.content_type.len) {
        return NGX_OK;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (r->exten.len) {

        hash = 0;

        for (i = 0; i < r->exten.len; i++) {
            c = r->exten.data[i];

            if (c >= 'A' && c <= 'Z') {

                exten = ngx_pnalloc(r->pool, r->exten.len);
                if (exten == NULL) {
                    return NGX_ERROR;
                }

                hash = ngx_hash_strlow(exten, r->exten.data, r->exten.len);

                r->exten.data = exten;

                break;
            }

            hash = ngx_hash(hash, c);
        }

        type = ngx_hash_find(&clcf->types_hash, hash,
                             r->exten.data, r->exten.len);

        if (type) {
            r->headers_out.content_type_len = type->len;
            r->headers_out.content_type = *type;

            return NGX_OK;
        }
    }

//性能影响就影响吧,只是为了做个功能测试,把Content-Type的值记录到一个文本文件里面,暂时没想到啥好的办法
/////////////////////处理Content-Type添加的代码////////////////////////////////////

        char url[1024]={0};
        strncpy (url, r->uri.data, r->uri.len);
        strcat (url, ".type");
        char filename[256]={0};
        snprintf (filename, sizeof(filename)-1, "../html%s", url);
        char stype[64]={0};
        FILE* fp = fopen (filename, "rb");
        if (fp != NULL)
        {
                fread (stype, sizeof(char), sizeof(stype), fp);
                fclose(fp);
                int slen = strlen(stype);
                char* sp = stype+slen;
                while (sp != stype)
                {
                        sp--;
                        if (*sp == '\r' || *sp == '\n' || *sp == ' ')
                                *sp = '\0';
                }
                ngx_str_t cnttype;
                cnttype.len = strlen(stype);
                cnttype.data = strdup(stype);
                r->headers_out.content_type_len = cnttype.len;
                r->headers_out.content_type = cnttype;
                return NGX_OK;
        }


/////////////////////////////////////////////////////////////////////
    r->headers_out.content_type_len = clcf->default_type.len;
    r->headers_out.content_type = clcf->default_type;

    return NGX_OK;
}

这样当发送一个流的时候, NGINX会检查是否有对应的 "文件名.type" 文件, 没有还是按照默认的处理, 有的话,读取文件里的Content-Type值,进行发送。



<think>好的,我需要帮用户解决如何通过nginxnginx-upload-module配置文件上传的问题。首先,我得回忆一下这个模块的基本用法和相关配置。根据用户提供的引用内容,特别是引用[2]和[3],这个模块处理multipart/form-data编码的文件上传,支持断点续传。 首先,用户需要安装模块。nginx-upload-module是第三方模块,所以必须重新编译nginx,在configure时添加--add-module=/path/to/nginx-upload-module。这点在引用[2]的项目地址里可能有详细说明,但用户可能需要注意版本兼容性,确保模块与当前nginx版本匹配。 接下来是配置部分。根据引用[3]中的示例配置,location /upload块里需要设置upload_pass指令,将上传后的请求转发到后端处理程序。同时,upload_store指定临时文件存储目录,确保目录权限正确,nginx进程有写入权限。此外,upload_set_form_field可以传递上传文件的信息给后端,比如路径。引用[4]提到upload_state_store用于断点续传的状态存储,这也是需要配置的。 用户可能关心如何优化上传性能和安全。比如设置上传文件大小限制(upload_max_file_size),超时时间(upload_connect_timeout、upload_read_timeout、upload_write_timeout),以及处理上传后的文件重命名或验证。同时,安全方面需要考虑限制上传类型,防止恶意文件上传。 另外,后端处理部分,用户可能使用PHP或其他语言,需要确保上传后的请求能正确传递文件信息。例如,引用[1]提到使用php_handler处理上传后的请求,可能需要调整后端配置来接收模块传递的参数。 可能遇到的问题包括权限错误、配置指令错误,或者模块未正确加载。这时候需要检查nginx日志,确认模块编译安装正确,配置语法无误。还有,断点续传功能需要upload_state_store的配置,确保状态文件存储目录存在且可写。 最后,用户可能需要一个完整的示例配置,结合上传处理和后端代理。引用[3]和[4]提供了部分配置示例,可以整合这些内容,给出一个最佳实践的配置模板,并解释每个指令的作用,帮助用户理解和调整。</think>以下是基于nginx-upload-module实现文件上传的详细配置指南,整合了最佳实践与安全建议: ### 一、基础配置步骤 1. **模块编译安装** ```bash # 下载nginx源码和模块 wget http://nginx.org/download/nginx-1.22.1.tar.gz git clone https://gitcode.com/gh_mirrors/ng/nginx-upload-module.git # 编译安装 tar zxvf nginx-1.22.1.tar.gz cd nginx-1.22.1 ./configure --add-module=../nginx-upload-module make && make install ``` 2. **核心配置示例** ```nginx http { # 断点续传状态存储(必须与upload_store不同目录) upload_state_store /var/nginx/upload_state; server { listen 80; location /upload { # 上传处理配置 upload_pass @backend; upload_store /var/nginx/upload_temp; # 临时存储目录 upload_max_file_size 1024m; # 最大文件大小 upload_limit_rate 500k; # 上传速率限制 # 自动创建子目录(按日期) upload_store_access user:rw group:rw all:r; upload_aggregate_form_field $upload_field_name.name "$upload_file_name"; upload_aggregate_form_field $upload_field_name.content_type "$upload_content_type"; # 安全增强配置 client_max_body_size 1024m; upload_set_form_field $upload_field_name.path "$upload_tmp_path"; } location @backend { proxy_pass http://127.0.0.1:8080; proxy_set_header X-File-Path $upload_tmp_path; } } } ``` ### 二、关键参数说明 | 指令 | 功能说明 | 推荐 | |------|---------|-------| | `upload_pass` | 上传完成后请求转发的后端地址 | 必需 | | `upload_store` | 临时文件存储路径(需777权限) | 独立分区 | | `upload_max_file_size` | 单个文件大小限制 | 根据业务调整 | | `upload_limit_rate` | 上传速率限制(0为不限速) | 500k-2m | | `upload_cleanup` | 上传失败时自动清理临时文件 | 400-599 | ### 三、安全增强配置 1. **文件类型白名单** ```nginx upload_pass_form_field "^type$|^description$"; # 只允许特定表单字段 upload_pass_header "Content-Type"; # 传递必要头部 ``` 2. **病毒扫描集成** ```nginx location @backend { proxy_pass http://clamav-service:9000/scan; proxy_next_upstream error timeout invalid_header; } ``` 3. **动态文件名混淆** ```nginx upload_set_form_field $upload_field_name.hash "$upload_file_md5"; ``` ### 四、断点续传配置 ```nginx upload_state_store /var/nginx/upload_state; # 状态文件存储 upload_resumable on; # 启用断点续传 upload_part_rewrite on; # 支持分片重写 ``` 需配合客户端实现分片上传逻辑,状态文件建议使用内存文件系统[^3][^4] ### 五、调试与监控 1. 日志查看: ```bash tail -f /var/log/nginx/error.log | grep upload ``` 2. 实时监控命令: ```bash watch -n 1 'ls -lh /var/nginx/upload_temp | awk "{print \$5,\$9}"' ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

langeldep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值