随笔 - 2082  文章 - 4  评论 - 249 

Nginx与X-Sendfile

X-accel模块允许由后台通过返回的头来决定投递静态文件。为什么要这么做呢?试想一下我们经常碰到的这种情况,在有的论坛中,下载资源需要登录认证、权限核查、积分扣除或者是积分增加等等,对于Nginx来说这些细粒度的控制其本身无法完成,因此需要应用程序来完成,当应用程序完成这些操作后,根据实际情况会做出选择,如果条件满足那么开始下载所要获取的静态资源(文件),注意,这是由动态的程序提供下载,对于动态程序来说,这是一个弱点,而对于Nginx来说,这是它的强项,那么在这种形式下能不能让Nginx来完成静态资源的下载呢?答案是可以的。但我们为什么有必要这么做呢?答案在于Nginx在打开静态文件上使用了sendfile(2),因此其IO效率非常之高。

 

处理流程

 

    具体的处理流程是:

 

   

     -------------------------

     |"GET /dd/filename  |

     |                           |

    ∨                          |

  客户端请求----------->Nginx----->Backend(Apache、Tomcat、FastCGI,……)

                               ∧                                                                |

                                |                                                                 |

                                |  X-Accel-Redirect: /files/filename                   |

                                |_______________________________________|

  

    我们从这个流程图中不难看出在客户端的请求被转向后台服务器时,服务器并没有为客户端返回实际要下载的资源(而是去做了其它的验证或者是其它的工作)而是使用了X-Accel-Redirect头将下载的资源又传递给了Nginx,最后又是通过Nginx服务器处理该请求发送给客户端。

 

    这种功能就是我们说的X-Sendfile,在Nginx中由X-Accel-Redirect来完成,在后台服务器将下载的请求抛给Nginx后,那么后台的服务器又可以承接其它的活进而处理其它的请求了,因此大大的减轻了后端服务器的压力。

 

    相对于其它的Nginx来说,X-accel模块与其它标准的Nginx模块有所不同,它的实现不是依赖于指令而是依赖于在特定方式下后台(或者叫上游)服务器发回的请求头,它的方法我们在前面也了解到了,就是通过发送一个带有URI的x-accel-redirect头,Nginx将会将这个请求作为正常(这里的正常就是指就像是使用浏览器一样的请求)的请求来处理这个请求,然后根据这个URI进行location匹配,然后是请求文件的匹配,最终实现的是在后端服务器返回的请求头中:“root + URI”与Nginx中location匹配,这里的“root”,我们以PHP程序为例:

 

header("X-Accel-Redirect: /files/" . $path);

   

    就是我们这个PHP程序中的“/files/”部分,而URI则是“$path”部分。在这里我们就了解到这里,在后面的例子会证实这一点。

 

    另外,还需要注意一点,由于Nginx服务器只认识从后端服务器发来的X-Accel-Redirect头,而从客户端发来的这种头,它并不理睬。

 

配置示例

 

# Will serve /var/www/files/myfile.tar.gz

# When passed URI /protected_files/myfile.tar.gz

location /protected_files {

    internal;

    alias /var/www/files;

}

 

# Will serve /var/www/protected_files/myfile.tar.gz

# When passed URI /protected_files/myfile.tar.gz

location /protected_files {

    internal;

    root /var/www;

}

 

You can also proxy to another server.

 

location /protected_files {

    internal;

    proxy_pass http://127.0.0.2;

}

 

posted on 2015-01-28 09:19  duanxz  阅读(2346)  评论(0编辑  收藏