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

论坛 期权论坛     
选择匿名的用户   2021-5-23 02:01   36   0
<p>本文将学些开发一个简单的HTTP过滤模块,它能够对Content-Type为text/plain的包体前加上前缀字符串prefix.</p>
<p>&lt;一&gt; 过滤模块的调用顺序</p>
<p>过滤模块可以叠加,也就是说一个请求会被所有的HTTP过滤模块依次处理。</p>
<p>过滤模块的调用时有顺序的,它的顺序在编译的时候就决定了。控制编译的脚本位于auto/modules中,当你编译完Nginx以后,可以再objs目录下面看到一个ngx_modules.c的文件,打开这个文件,有类似的代码:</p>
<pre class="blockcode"><code class="language-html">ngx_module_t *ngx_modules[] &#61; {
  ...
  &amp;ngx_http_write_filter_module,
  &amp;ngx_http_header_filter_module,
  &amp;ngx_http_chunked_filter_module,
  &amp;ngx_http_range_header_filter_module,
  &amp;ngx_http_gzip_filter_module,
  &amp;ngx_http_postpone_filter_module,
  &amp;ngx_http_ssi_filter_module,
  &amp;ngx_http_charset_filter_module,
  &amp;ngx_http_userid_filter_module,
  &amp;ngx_http_headers_filter_module,
  &amp;ngx_http_copy_filter_module,
  &amp;ngx_http_range_body_filter_module,
  &amp;ngx_http_not_modified_filter_module,
  NULL
};</code></pre>
<p>从write_filter到not_modified_filter,模块的执行顺序是反向的。也就是说最早执行的是not_modified_filter,然后各个模块以此执行。所有第三方的模块只能加入到copy_filter和headers_filter模块之间执行。</p>
<p>在编译Nginx源码时,已经定义了一个由所有HTTP过滤模块组成的单链表,这个单链表是这样的:</p>
<pre class="blockcode"><code class="language-html">链表的每个元素都是一个C源代码文件,这个C源代码文件中有两个指针,分别指向下一个过滤模块(文件)的过滤头部和包体的方法(可理解为链表中的next指针)</code></pre>
<p>过滤模块单链表示意图:</p>
<p><img alt="" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-e18a91f8b7ff56a466920e2ea8f2a142"><br></p>
<p>这两个指针的声明如下:</p>
<pre class="blockcode"><code class="language-html">/*过滤模块处理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);</code></pre>
<p>在我们定义的第三方模块中则有如下声明:</p>
<pre class="blockcode"><code class="language-html">static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;</code></pre>
<p>那么怎么将这个源文件(节点),插入到HTTP过滤模块组成的单链表中去呢?Nginx采用头插法的办法,所有的新节点都插入在链表的开头:</p>
<pre class="blockcode"><code class="language-html">//插入到头部处理方法链表的首部
ngx_http_next_header_filter&#61;ngx_http_top_header_filter;
ngx_http_top_header_filter&#61;ngx_http_myfilter_header_filter;
//插入到包体处理方法链表的首部
ngx_http_next_body_filter&#61;ngx_http_top_body_filter;
ngx_http_top_body_filter&#61;ngx_http_myfilter_body_filter;</code></pre>
<p>其中,两个top指针声明如下:</p>
<pre class="blockcode"><code class="language-html">extern ngx_http_output_header_filter_pt ngx_http_next_header_filter;
extern ngx_http_output_body_filter_pt ngx_http_next_body_filter;</code></pre>
<p>由于是头插法,这样就解释了,越早插入链表的过滤模块,就会越晚执行。</p>
<p>&lt;二&gt; 开发一个简单的过滤模块</p>
<p>要开发一个简单的过滤模块,它的功能是对Content-Type为text/plain的响应添加一个前缀,类似于开发一个HTTP模块,它应该遵循如下步骤:</p>
<pre class="blockcode"><code class="language-html">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.中提到两个处理头部和包体的方法。</code></pre>
<p>接下来按照上述步骤依次来实现:</p>
<p>2.1 确定源代码文件目录,编写config文件</p>
<p>config文件如下:</p>
<pre class="blockcode"><code class="language-html">ngx_addon_name&#61;ngx_http_myfilter_module
HTTP_FILTER_MODULES&#61;&#34;$HTTP_FILTER_MODULES ngx_http_myfilter_module&#34;
NGX_ADDON_SRCS&#61;&#34;$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_myfilter_module.c&#34;</code></pre>
<p>2.2 定义过滤模块,实例化ngx_module_t</p>
<pre class="blockcode"><code class="language-html">/*定义过滤模块,ngx_module_t结构体
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP