<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nginx on Mer's Blog</title><link>https://merisky.top/tags/nginx/</link><description>Recent content in Nginx on Mer's Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 28 Mar 2023 19:34:18 +0800</lastBuildDate><atom:link href="https://merisky.top/tags/nginx/index.xml" rel="self" type="application/rss+xml"/><item><title>Nginx 多阶段 Http 请求处理流程</title><link>https://merisky.top/posts/649054200/</link><pubDate>Mon, 11 Apr 2022 09:42:32 +0000</pubDate><guid>https://merisky.top/posts/649054200/</guid><description>&lt;p&gt;Nginx 通过将各个阶段的所有模块按序的组织成一条执行链，以流水线的形式依次进行处理。&lt;/p&gt;&#10;&lt;h2 id="执行链及流程"&gt;&lt;a href="#执行链及流程" class="headerlink" title="执行链及流程"&gt;&lt;/a&gt;执行链及流程&lt;/h2&gt;&lt;p&gt;nginx执行链的定义如下：&lt;/p&gt;&#10;&lt;figure class="highlight c"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;typedef&lt;/span&gt; &lt;span class="class"&gt;&lt;span class="keyword"&gt;struct&lt;/span&gt; &amp;#123;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; &lt;span class="type"&gt;ngx_http_phase_handler_t&lt;/span&gt; *handlers; &lt;span class="comment"&gt;/*执行链*/&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; &lt;span class="type"&gt;ngx_uint_t&lt;/span&gt; server_rewrite_index;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; &lt;span class="type"&gt;ngx_uint_t&lt;/span&gt; location_rewrite_index;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&amp;#125; &lt;span class="type"&gt;ngx_http_phase_engine_t&lt;/span&gt;;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p&gt;执行链节点的数据结构定义如下：&lt;/p&gt;&#10;&lt;figure class="highlight c"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="class"&gt;&lt;span class="keyword"&gt;struct&lt;/span&gt; &lt;span class="title"&gt;ngx_http_phase_handler_s&lt;/span&gt; &amp;#123;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; ngx_http_phase_handler_pt checker;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; ngx_http_handler_pt handler;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; &lt;span class="type"&gt;ngx_uint_t&lt;/span&gt; next;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&amp;#125;;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p&gt;对于执行链节点，相同阶段具有相同的checker函数，handler中则保存的是挂载至该阶段的模块处理函数，一般在checker函数中会执行当前节点的handler函数&lt;/p&gt;&#10;&lt;p&gt;执行链的执行流程是按照执行链顺序向前执行，但某个阶段需要回跳或跳过之后的某些执行阶段，next字段保存的就是跳跃的目的索引。&lt;/p&gt;&#10;&lt;p&gt;各个阶段如下：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;NGX_HTTP_POST_READ_PHASE&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;接受完请求头之后的第一个阶段，位于uri重写之前，默认情况下该阶段被跳过;&lt;/p&gt;&#10;&lt;p&gt;nginx源码中仅有realip模块在POST_READ阶段对客户端ip进行了替换，且该模块并未被默认编译进nginx&lt;/p&gt;&#10;&lt;p&gt;POST_HEAD阶段的checker函数仅调用对应的handler函数，随后对返回值进行处理，当handler返回NGX_OK时进入下一阶段&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;NGX_HTTP_SERVER_REWRITE_PHASE&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;server级别的uri重写阶段，执行于server块内，location块外的重写指令。&lt;/p&gt;&#10;&lt;p&gt;nginx的rewrite模块在此阶段提供url重写指令rewrite和变量指令set，以及逻辑控制指令if、break和return以供用户完成一些简单的需求而不必注册handler&lt;/p&gt;&#10;&lt;p&gt;该阶段的请求未被匹配至具体的location中&lt;/p&gt;&#10;&lt;p&gt;SERVER_REWRITE阶段的checker函数同样调用handler函数，但处理方式稍有不同，当handler返回NGX_DECLINED时进入下一阶段&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;NGX_HTTP_FIND_CONFIG_PHASE&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;这一阶段根据重写过的uri查找对应的location，可能被执行多次&lt;/p&gt;&#10;&lt;p&gt;通过ngx_http_core_find_location函数完成对r-&amp;gt;loc_conf的设置，然后调用ngx_http_update_location_config更新请求相关配置&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;NGX_HTTP_REWRITE_PHASE&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;location级别的重写阶段，该阶段执行location基本的重写指令，可能被执行多次。&lt;/p&gt;&#10;&lt;p&gt;与SERVER_REWRITE的逻辑基本相同，使用相同的handler函数，只是执行的时机不同。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;NGX_HTTP_POST_REWRITE_PHASE&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;该阶段不能挂载handler，仅用于检查REWRITE阶段是否进行uri重写，若发生重写则返回再次执行REWRITE阶段，默认限制的重写次数为10次&lt;/p&gt;</description></item></channel></rss>