试想一下这样一个需求:

在使用nginx反向代理的时候,我们需要缓存从后端服务器拉取的内容,正常情况下,如果所需要的内容就在后端服务器上,那么很容易,使用nginx的

proxy_cache模块就能够实现缓存。但是有一种情况:内容没有在后端服务器上,而是从后端服务器返回了一个重定向地址,重定向到了第三方服务器,

那么这时候nginx缓存下来的内容就是不是我们需要的源内容了,而是一个只包含重定向链接的文件,那么我们如何应对这一情况呢?



X-accel允许在nginx内部重定向到一个从后端服务器返回的地址,这个功能能够取代你在后端服务器处理一些鉴权、登陆或者其他的事情,并且还能够

让nginx处理那些从重定向地址到终端(浏览器)的内容,这样一来,在后端服务器中,你就能够处理更多的其它的请求。这种功能就是我们常常提到的

X-Sendfile。

这一特性不同于标准的nginx模块,因为它不依赖于标准的协议指令而是以一种特殊的方式处理来自于上游服务器的http消息头,我们采用的方法就是在

你发送一个头消息的时候,携带上一个x-accel-redirect属性的uri,当nginx接收到这个消息头的时候,发现具有x-accel-redirect属性,那么将会把它当做

一个正常的请求(类似于浏览器访问nginx)使用后面携带的uri和当前nginx配置文件中的location进行匹配,然后,nginx将会指向和消息头部中uri相匹配的location。



下面为一个配置实例

#user  nobody;
worker_processes  1;
error_log   logs/error.log  debug;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;  
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    proxy_cache_path /home/mpeg/cache/nginx levels=1:2 keys_zone=ts:500m max_size=1g;
    server {
        listen       8889;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        add_header X-Via $server_addr;
        add_header X-Cache $upstream_cache_status;
        location / {
            proxy_pass http://192.168.15.159:8999;
	    proxy_set_header  X-Real-IP  $remote_addr;
	    proxy_cache ts;
      	    proxy_cache_valid 200 302 24h;
        }
        location ~* ^/internal_redirect/(.*?)/(.*) {
	    internal;
	    proxy_set_header  X-Real-IP  $remote_addr;
	    proxy_cache ts;
      	    proxy_cache_valid 200 302 24h;
	    # Extract download url from the request
	    set $download_uri $2;
	    set $download_host $1;
 	    # Compose download url
  	    set $download_url $download_host/$download_uri;
	    proxy_pass $download_url;
	}
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

实际环境中一个demo


#user  nobody;
worker_processes  8;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;

error_log   logs/error.log  notice;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    proxy_cache_path /home/mpeg/cache/nginx levels=1:2 inactive=1h keys_zone=ts:500m max_size=2g;
    server {
        listen       8889;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        add_header X-Cache $upstream_cache_status;
	#cache for redirect ts:/internal_redirect/http://192.168.15.159:7090/home/mpeg/record_ott/143252147.ts
	#cache for redirect vmhls:/internal_redirect/http://192.168.15.159:7090/vmhls?&filename=/home/mpeg/cl/052_800&startoffset=93717248&endoffset=98178864
        location ~* ^/internal_redirect/(.*?)/(.*) {
	    internal;
	    proxy_set_header  X-Real-IP  $remote_addr;
	    proxy_cache ts;
      	    proxy_cache_valid 200 302 24h;
	    # Extract download url from the request
	    set $download_uri $2;
	    set $download_host $1;
 	    # Compose download url
  	    set $download_url $download_host/$download_uri?$args;
	    proxy_pass $download_url;
	}
	location ~* live {

		#no cache for sub m3u8:/live/0000000000010078.m3u8?&nodename=cl&usercode=192_168_15_111_0000000000010078...
		#no cache for main m3u8:/live/1.m3u8
		location ~* .m3u8 {
	            proxy_pass http://192.168.15.110:8999;
		    proxy_set_header  X-Real-IP  $remote_addr;
	       }
		#cache for ts:/live/0000000000010078/1.ts?&nodename=cl&usercode=192_168_15_111_0000000000010078...
	        location ~* .ts {
	            proxy_pass http://192.168.15.110:8999;
		    proxy_set_header  X-Real-IP  $remote_addr;
		    proxy_cache ts;
	      	    proxy_cache_valid 200 302 24h;
	        }
	}
	location ~* vod {

		#no cache for sub m3u8:/vod/000000000010078_800.m3u8
		#no cache for main m3u8:/vod/000000000010078.m3u8
		location ~* .m3u8 {
	            proxy_pass http://192.168.15.110:8999;
		    proxy_set_header  X-Real-IP  $remote_addr;
	       }
		#cache for tss:/vod/000000000010052_800&startoffset=0&endoffset=4463308/1.ts 
	        location ~* .ts {
	            proxy_pass http://192.168.15.110:8999;
		    proxy_set_header  X-Real-IP  $remote_addr;
		    proxy_cache ts;
	      	    proxy_cache_valid 200 302 24h;
	        }
	}
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}







说明一下:假如在返回给nginx的header消息中有如下设置


X-Accel-Redirect: /internal_redirect/http://192.168.15.110:7090/home/mpeg/cl/1.ts




那么,经过上述匹配,能够得到如下结果:


$1 = http:/
$2 = /192.168.15.110:7090/home/mpeg/cl/1.ts
$download_url = http://192.168.15.110:7090/home/mpeg/cl/1.ts



这是正则表达式匹配的结果。


最后来看一下整个执行流程:


假设客户端(192.168.15.13)、nginx(192.168.15.14:8889)、后端服务器(192.168.15.159:8999)、第三方服务器(192.168.15.160)


数据流应该是这样的

客户端--->nginx--->后端服务器---(重定向第三方服务器,将第三方服务器地址返回给nginx)--->nginx---(nginx识别X-Accel-Redirect并且访问它指向的重定向连接)
      |
同时返回给客户端<---- --------------------------    nginx下载内容并且缓存到本    <-----------------------------------------|




最后关于清理缓存文件,这里没必要使用缓存清理模块,只需要使用一条命令:


find ./ -maxdepth 2 -type f -mmin +100 | xargs -n 1 rm -f



当然,如果proxy cache模块自带的清理缓存文件的功能满足你的要求的话,那你也可使用自带的功能情路缓存