您的位置:首页 > 理论基础 > 计算机网络

Nginx开发一个简单的HTTP过滤模块

2017-04-26 18:23 716 查看
转载:http://blog.csdn.net/zhangxiao93/article/details/53691642

记录为了学习

开发一个HTTP过滤模块的步骤和相关知识跟开发一个普通的HTTP模块是类似的,只不过HTTP过滤模块的地位、作用与正常的HTTP过滤模块不同,它的工作是对发送给用户的HTTP响应包做一些加工。

本文将学习开发一个简单的HTTP过滤模块,它能够对
Content-Type为text/plain
的包体前加上前缀字符串prefix。

一过滤模块的调用顺序
二开发一个简单的过滤模块
1 确定源代码文件目录编写config文件
2 定义过滤模块实例化ngx_module_t
3 处理感兴趣的配置项
4 实现初始化方法
5 实现头部和包体过滤方法
51 函数声明
52 函数实现

三完整代码与测试
1 完整代码
2 测试

四参考



(一)过滤模块的调用顺序
过滤模块可以叠加,也就是说一个请求会被所有的HTTP过滤模块依次处理。

过滤模块的调用是有顺序的,它的顺序在编译的时候就决定了。控制编译的脚本位于
auto/modules
中,当你编译完Nginx以后,可以在objs目录下面看到一个ngx_modules.c的文件。打开这个文件,有类似的代码:
ngx_module_t *ngx_modules[] = {
...
&ngx_http_write_filter_module,
&ngx_http_header_filter_module,
&ngx_http_chunked_filter_module,
&ngx_http_range_header_filter_module,
&ngx_http_gzip_filter_module,
&ngx_http_postpone_filter_module,
&ngx_http_ssi_filter_module,
&ngx_http_charset_filter_module,
&ngx_http_userid_filter_module,
&ngx_http_headers_filter_module,
&ngx_http_copy_filter_module,
&ngx_http_range_body_filter_module,
&ngx_http_not_modified_filter_module,
NULL
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

write_filter
not_modified_filter
,模块的执行顺序是反向的。也就是说最早执行的是
not_modified_filter
,然后各个模块依次执行。所有第三方的模块只能加入到
copy_filter
headers_filter
模块之间执行。

在编译Nginx源码时,已经定义了一个由所有HTTP过滤模块组成的单链表,这个单链表是这样的:

链表的每一个元素都是一个C源代码文件,这个C源代码文件中有两个指针,分别指向下一个过滤模块(文件)的过滤头部和包体的方法(可理解为链表中的next指针)

过滤模块单链表示意图: 



这两个指针的声明如下:
/*过滤模块处理HTTP头部的函数指针类型定义,它携带一个参数:请求*/
typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
/*过滤模块处理HTTP包体的函数指针类型定义,它携带两个参数:请求、要发送的包体*/
typedef ngx_int_t (*ngx_http_output_body_filter_pt)
(ngx_http_request_t *r, ngx_chain_t *chain);
1
2
3
4
5
1
2
3
4
5

在我们定义的第三方模块中则有如下声明:
/*用static修饰只在本文件生效,因此允许所有的过滤模块都有自己的这两个指针*/
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
1
2
3
1
2
3

那么怎么将这个源文件(节点),插入到HTTP过滤模块组成的单链表中去呢? 

Nginx采用头插法的办法,所有的新节点都插入在链表的开头:
//插入到头部处理方法链表的首部
ngx_http_next_header_filter=ngx_http_top_header_filter;
ngx_http_top_header_filter=ngx_http_myfilter_header_filter;
//插入到包体处理方法链表的首部
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_myfilter_body_filter;
1
2
3
4
5
6
1
2
3
4
5
6

其中两个top指针声明如下:
extern ngx_http_output_header_filter_pt ngx_http_next_header_filter;
extern ngx_http_output_body_filter_pt ngx_http_next_body_filter;
1
2
1
2

由于是头插法,这样就解释了,越早插入链表的过滤模块,就会越晚执行。



(二)开发一个简单的过滤模块
要开发一个简单的过滤模块,它的功能是对
Content-Type
text/plain
的响应添加一个前缀,类似于开发一个HTTP模块,它应该遵循如下步骤:

1.确定源代码文件名称,源代码所在目录创建
config
脚本文件,
config
文件的编写方式跟HTTP模块开发基本一致,不同的是需要将
HTTP_MODULES
改成
HTTP_FILTER_MODULES


2.定义过滤模块。实例化
ngx_module_t
类型模块结构,因为HTTP过滤模块也是HTTP模块,所以其中的type成员也是
NGX_HTTP_MODULE


3.处理感兴趣的配置项,通过设置
ngx_module_t
中的
ngx_command_t
数组来处理感兴趣的配置项。

4.实现初始化方法。初始化方法就是把本模块中处理HTTP头部的
ngx_http_output_header_filter_pt
方法和处理HTTP包体的
ngx_http_output_body_filter_pt
方法插入到过滤模块链表的首部。

5.实现4.中提到两个处理头部和包体的方法。

接下来按照上述步骤依次来实现:


2.1 确定源代码文件目录,编写config文件

config 文件如下
ngx_addon_name=ngx_http_myfilter_module
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_myfilter_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_myfilter_module.c"
1
2
3
1
2
3


2.2 定义过滤模块,实例化ngx_module_t

/*定义过滤模块,ngx_module_t结构体实例化*/
ngx_module_t ngx_http_myfilter_module =
{
NGX_MODULE_V1,                 /*Macro*/
&ngx_http_myfilter_module_ctx,         /*module context*/
ngx_http_myfilter_commands,            /*module directives*/
NGX_HTTP_MODULE,                       /* module type */
NULL,                                  /* init master */
NULL,                                  /* init module */
NULL,                                  /* init process */
NULL,                                  /* init thread */
NULL,                                  /* exit thread */
NULL,                                  /* exit process */
NULL,                                  /* exit master */
NGX_MODULE_V1_PADDING                  /*Macro*/
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


2.3 处理感兴趣的配置项

/*处理感兴趣的配置项*/
static ngx_command_t ngx_http_myfilter_commands[]=
{
{
ngx_string("add_prefix"), //配置项名称
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_FLAG,//配置项只能携带一个参数并且是on或者off
ngx_conf_set_flag_slot,//使用nginx自带方法,参数on/off
NGX_HTTP_LOC_CONF_OFFSET,//使用create_loc_conf方法产生的结构体来存储
//解析出来的配置项参数
offsetof(ngx_http_myfilter_conf_t, enable),//on/off
NULL
},
ngx_null_command //
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14

其中定义结构体
ngx_http_myfilter_conf_t
来保存配置项参数:
typedef struct
{
ngx_flag_t enable;
}ngx_http_myfilter_conf_t;
1
2
3
4
1
2
3
4


2.4 实现初始化方法

头插入法将本过滤模块插入到单链表的首部:
/*初始化方法*/
static ngx_int_t
ngx_http_myfilter_init(ngx_conf_t*cf)
{

//插入到头部处理方法链表的首部 ngx_http_next_header_filter=ngx_http_top_header_filter; ngx_http_top_header_filter=ngx_http_myfilter_header_filter; //插入到包体处理方法链表的首部 ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_myfilter_body_filter;
}
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12


2.5 实现头部和包体过滤方法


2.5.1 函数声明

/*头部处理方法*/
static ngx_int_t
ngx_http_myfilter_header_filter(ngx_http_request_t *r);

/*包体处理方法*/
static ngx_int_t
ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in);
1
2
3
4
5
6
7
1
2
3
4
5
6
7


2.5.2 函数实现

(1)头部处理方法:最终处理效果头部信息
Content-Length
的值加上prefix的长度。
/*头部处理方法*/
static ngx_int_t
ngx_http_myfilter_header_filter(ngx_http_request_t *r)
{
ngx_http_myfilter_ctx_t *ctx;
ngx_http_myfilter_conf_t *conf;
//如果不是返回成功,这时是不需要理会是否加前缀的,
//直接交由下一个过滤模块
//处理响应码非200的情形
if (r->headers_out.status != NGX_HTTP_OK)
{
return ngx_http_next_header_filter(r);
}

/*获取http上下文*/
ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);

if(ctx)
{
//该请求的上下文已经存在,这说明
// ngx_http_myfilter_header_filter已经被调用过1次,
//直接交由下一个过滤模块处理
return ngx_http_next_header_filter(r);
}

//获取存储配置项参数的结构体
conf = ngx_http_get_module_loc_conf(r, ngx_http_myfilter_module);

//如果enable成员为0,也就是配置文件中没有配置add_prefix配置项,
//或者add_prefix配置项的参数值是off,这时直接交由下一个过滤模块处理
if (conf->enable == 0)
{
return ngx_http_next_header_filter(r);
}

//conf->enable==1
//构造http上下文结构体ngx_http_myfilter_ctx_t
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_myfilter_ctx_t));
if(NULL==ctx)
{
return NGX_ERROR;
}
ctx->add_prefix=0;
ngx_http_set_ctx(r,ctx,ngx_http_myfilter_module);

//只处理Content-Type是"text/plain"类型的http响应
if (r->headers_out.content_type.len >= sizeof("text/plain") - 1
&& ngx_strncasecmp(r->headers_out.content_type.data, (u_char *) "text/plain", sizeof("text/plain") - 1) == 0)
{
ctx->add_prefix=1;
if(r->headers_out.content_length_n > 0)
{
r->headers_out.content_length_n+=filter_prefix.len;
}
}
//交由下一个过滤模块继续处理
return ngx_http_next_header_filter(r);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

(2)响应包体处理方法:最终处理效果在包体前面添加前缀。
/*包体处理方法*/
static ngx_int_t
ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_myfilter_ctx_t *ctx;

ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);

//如果获取不到上下文,或者上下文结构体中的add_prefix为0或者2时,
//都不会添加前缀,这时直接交给下一个http过滤模块处理
if (ctx == NULL || ctx->add_prefix != 1)
{
return ngx_http_next_body_filter(r, in);
}

//将add_prefix设置为2,这样即使ngx_http_myfilter_body_filter
//再次回调时,也不会重复添加前缀
ctx->add_prefix = 2;

//从请求的内存池中分配内存,用于存储字符串前缀
ngx_buf_t* b = ngx_create_temp_buf(r->pool, filter_prefix.len);

//将ngx_buf_t中的指针正确地指向filter_prefix字符串
b->start = b->pos = filter_prefix.data;
b->last = b->pos + filter_prefix.len;

//从请求的内存池中生成ngx_chain_t链表,将刚分配的ngx_buf_t设置到
//其buf成员中,并将它添加到原先待发送的http包体前面
ngx_chain_t *cl = ngx_alloc_chain_link(r->pool);
/*note: in表示原来待发送的包体*/
cl->buf = b;
cl->next = in;

//调用下一个模块的http包体处理方法,注意这时传入的是新生成的cl链表
return ngx_http_next_body_filter(r, cl);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37



(三)完整代码与测试
至此,已经完成大部分的工作,我们还需要为这个过滤模块编写模块上下文,编写创建和合并配置项参数结构体的函数等。


3.1 完整代码

/*ngx_http_myfilter_module.c*/

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

/*用static修饰只在本文件生效,因此允许所有的过滤模块都有自己的这两个指针*/ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter;

/*初始化方法,将过滤模块插入到链表头部*/
static ngx_int_t
ngx_http_myfilter_init(ngx_conf_t *cf);

/*头部处理方法*/ static ngx_int_t ngx_http_myfilter_header_filter(ngx_http_request_t *r); /*包体处理方法*/ static ngx_int_t ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in);

typedef struct { ngx_flag_t enable; }ngx_http_myfilter_conf_t;

/*请求上下文*/
typedef struct
{
ngx_int_t add_prefix;
}ngx_http_myfilter_ctx_t;

/*在包体中添加的前缀*/
static ngx_str_t filter_prefix=ngx_string("[my filter prefix]");

/*处理感兴趣的配置项*/ static ngx_command_t ngx_http_myfilter_commands[]= { { ngx_string("add_prefix"), //配置项名称 NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_FLAG,//配置项只能携带一个参数并且是on或者off ngx_conf_set_flag_slot,//使用nginx自带方法,参数on/off NGX_HTTP_LOC_CONF_OFFSET,//使用create_loc_conf方法产生的结构体来存储 //解析出来的配置项参数 offsetof(ngx_http_myfilter_conf_t, enable),//on/off NULL }, ngx_null_command // };

static void* ngx_http_myfilter_create_conf(ngx_conf_t *cf);
static char*
ngx_http_myfilter_merge_conf(ngx_conf_t *cf,void*parent,void*child);

/*模块上下文*/
static ngx_http_module_t ngx_http_myfilter_module_ctx=
{
NULL, /* preconfiguration方法 */
ngx_http_myfilter_init, /* postconfiguration方法 */

NULL, /*create_main_conf 方法 */
NULL, /* init_main_conf方法 */

NULL, /* create_srv_conf方法 */
NULL, /* merge_srv_conf方法 */

ngx_http_myfilter_create_conf, /* create_loc_conf方法 */
ngx_http_myfilter_merge_conf /*merge_loc_conf方法*/
};

/*定义过滤模块,ngx_module_t结构体实例化*/ ngx_module_t ngx_http_myfilter_module = { NGX_MODULE_V1, /*Macro*/ &ngx_http_myfilter_module_ctx, /*module context*/ ngx_http_myfilter_commands, /*module directives*/ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING /*Macro*/ };

static void* ngx_http_myfilter_create_conf(ngx_conf_t *cf)
{
ngx_http_myfilter_conf_t *mycf;

//创建存储配置项的结构体
mycf = (ngx_http_myfilter_conf_t *)ngx_pcalloc(cf->pool, sizeof(ngx_http_myfilter_conf_t));
if (mycf == NULL)
{
return NULL;
}

//ngx_flat_t类型的变量,如果使用预设函数ngx_conf_set_flag_slot
//解析配置项参数,必须初始化为NGX_CONF_UNSET
mycf->enable = NGX_CONF_UNSET;
return mycf;
}

static char*
ngx_http_myfilter_merge_conf(ngx_conf_t *cf,void*parent,void*child)
{
ngx_http_myfilter_conf_t *prev = (ngx_http_myfilter_conf_t *)parent;
ngx_http_myfilter_conf_t *conf = (ngx_http_myfilter_conf_t *)child;

//合并ngx_flat_t类型的配置项enable
ngx_conf_merge_value(conf->enable, prev->enable, 0);

return NGX_CONF_OK;

}

/*初始化方法*/
static ngx_int_t
ngx_http_myfilter_init(ngx_conf_t*cf)
{

//插入到头部处理方法链表的首部 ngx_http_next_header_filter=ngx_http_top_header_filter; ngx_http_top_header_filter=ngx_http_myfilter_header_filter; //插入到包体处理方法链表的首部 ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_myfilter_body_filter;
return NGX_OK;
}

/*头部处理方法*/
static ngx_int_t
ngx_http_myfilter_header_filter(ngx_http_request_t *r)
{
ngx_http_myfilter_ctx_t *ctx;
ngx_http_myfilter_conf_t *conf;
//如果不是返回成功,这时是不需要理会是否加前缀的,
//直接交由下一个过滤模块
//处理响应码非200的情形
if (r->headers_out.status != NGX_HTTP_OK)
{
return ngx_http_next_header_filter(r);
}

/*获取http上下文*/
ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);

if(ctx)
{
//该请求的上下文已经存在,这说明
// ngx_http_myfilter_header_filter已经被调用过1次,
//直接交由下一个过滤模块处理
return ngx_http_next_header_filter(r);
}

//获取存储配置项参数的结构体
conf = ngx_http_get_module_loc_conf(r, ngx_http_myfilter_module);

//如果enable成员为0,也就是配置文件中没有配置add_prefix配置项,
//或者add_prefix配置项的参数值是off,这时直接交由下一个过滤模块处理
if (conf->enable == 0)
{
return ngx_http_next_header_filter(r);
}

//conf->enable==1
//构造http上下文结构体ngx_http_myfilter_ctx_t
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_myfilter_ctx_t));
if(NULL==ctx)
{
return NGX_ERROR;
}
ctx->add_prefix=0;
ngx_http_set_ctx(r,ctx,ngx_http_myfilter_module);

//只处理Content-Type是"text/plain"类型的http响应
if (r->headers_out.content_type.len >= sizeof("text/plain") - 1
&& ngx_strncasecmp(r->headers_out.content_type.data, (u_char *) "text/plain", sizeof("text/plain") - 1) == 0)
{
ctx->add_prefix=1;
if(r->headers_out.content_length_n > 0)
{
r->headers_out.content_length_n+=filter_prefix.len;
}

}

//交由下一个过滤模块继续处理
return ngx_http_next_header_filter(r);
}

/*包体处理方法*/
static ngx_int_t
ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_myfilter_ctx_t *ctx;

ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);

//如果获取不到上下文,或者上下文结构体中的add_prefix为0或者2时,
//都不会添加前缀,这时直接交给下一个http过滤模块处理
if (ctx == NULL || ctx->add_prefix != 1)
{
return ngx_http_next_body_filter(r, in);
}

//将add_prefix设置为2,这样即使ngx_http_myfilter_body_filter
//再次回调时,也不会重复添加前缀
ctx->add_prefix = 2;
//从请求的内存池中分配内存,用于存储字符串前缀
ngx_buf_t* b = ngx_create_temp_buf(r->pool, filter_prefix.len);

//将ngx_buf_t中的指针正确地指向filter_prefix字符串
b->start = b->pos = filter_prefix.data;
b->last = b->pos + filter_prefix.len;

//从请求的内存池中生成ngx_chain_t链表,将刚分配的ngx_buf_t设置到
//其buf成员中,并将它添加到原先待发送的http包体前面
ngx_chain_t *cl = ngx_alloc_chain_link(r->pool);
/*note: in表示原来待发送的包体*/
cl->buf = b;
cl->next = in;

//调用下一个模块的http包体处理方法,注意这时传入的是新生成的cl链表
return ngx_http_next_body_filter(r, cl);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240


3.2 测试

我们的过滤模块只对
Content-Type
text/plain
的响应有效,查看Nginx的默认配置中的
mime.types
文件,发现
types{
#...
text/plain                            txt;
#...
}
1
2
3
4
5
1
2
3
4
5

也即当请求资源为txt时才会调用我们过滤模块,如果想要强制将响应的
Content-Type
设置为
text/plain
呢? 

只需要修改nginx.conf文件如下即可:
#user  root;
worker_processes  1;

error_log  logs/error.log  debug;

events {
worker_connections  1024;
}

http {
# 注释掉http块下的配置
#    include       mime.types;
#    default_type  application/octet-stream;

keepalive_timeout  65;

server {
listen 1024;

location / {
#在location块下将默认类型设置为text/plain
default_type text/plain;
root   html;
add_prefix on;
index index.htm index.html;
}

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

将自定义的过滤模块编译进Nginx:
./configure --add-module=/home/zhangxiao/nginx/nginx-1.0.15/src/myHttpFilterModule/
make;sudo make install
1
2
1
2

重启nginx,用curl工具进行测试
curl -v localhost:1024
1
1

可以看到返回的包体添加了前缀: 





(四)参考
1.《深入理解Nginx》 

2. Nginx开发从入门到精通
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: