Nginx使用X-Accel-Redirect实现静态文件下载的统计、鉴权、防盗链、限速等


Posted in Servers onApril 04, 2021

需求

  • 统计静态文件的下载次数;
  • 判断用户是否有下载权限;
  • 根据用户指定下载速度;
  • 根据Referer判断是否需要防盗链;
  • 根据用户属性限制下载速度;

X-Accel-Redirect

This allows you to handle authentication, logging or whatever else you please in your backend and then have NGINX handle serving the contents from redirected location to the end user, thus freeing up the backend to handle other requests. This feature is commonly known as X-Sendfile.
这个功能允许你在后端处理权限,日志或任何你想干的,Nginx提供内容服务给终端用户从重定向后的路径,因此可以释放后端去处理其他请求(直接由Nginx提供IO,而不是后端服务)。这个功能类似 X-Sendfile 。

不同 Web 服务器,相同功能,不同的标识:

nginx: X-Accel-Redirect 
squid: X-Accelerator-Vary 
apache: X-Sendfile 
lighttpd: X-Sendfile/X-LIGHTTPD-send-file 

X-Accel-Limit-Rate

限制下载速度,单位字节。默认不限速度。

X-Accel-Buffering

设置此连接的代理缓存,将此设置为no将允许适用于Comet和HTTP流式应用程序的无缓冲响应。将此设置为yes将允许响应被缓存。默认yes。

X-Accel-Expires

如果已传输过的文件被缓存下载,设置Nginx文件缓存过期时间,单位秒。默认不过期。

X-Accel-Charset

设置文件字符集,默认utf-8。

使用条件

  • 必须有Nginx作为后端服务的代理;
  • 必须访问Nginx的代理地址,直接访问后端服务Nginx会报404;
  • 可自行配置Content-Type来控制是下载(application/octet-stream)还是展示(image/jpeg等);

代码实现

  1. Nginx监听15555端口。
  2. Nginx代理后端服务的18000端口。
  3. 设置/file路径为internal,指定具体文件存储的磁盘位置。
  4. 后端服务接收到文件下载请求,处理业务逻辑后X-Accel-Redirect/file路径。
  5. Nginx收到后端返回信息中的X-Accel-Redirect请求头,接管文件下载任务。
  6. 请求路径:http://localhost:15555/f/1.jpg

Java-SpringMVC版本

Nginx配置

server {
    listen 15555;

    location / {
        proxy_redirect off;
        proxy_set_header Host  $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:18000/;            
    }

    location /file {
        internal;
        alias /data/file;
    }
}

Java代码

注意fileName添加:.+,或者获取不到文件后缀名。

@GetMapping(value = "/f/{fileName:.+}")
public void file(@PathVariable String fileName, HttpServletResponse response, HttpServletRequest request) throws IOException {
    //统计
    //鉴权
    //判断Referer
    String referer = request.getHeader("Referer");
    if (referer == null || !referer.startsWith("https://www.zhangbj.com")) {
        response.sendError(403, "Forbidden");
        return;
    }
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
    response.setHeader("Content-Type", "application/octet-stream");
    response.setHeader("X-Accel-Redirect","/file/" + fileName);
    response.setHeader("X-Accel-Limit-Rate","1024");//限速,单位字节,默认不限
    response.setHeader("X-Accel-Buffering","yes");//是否使用Nginx缓存,默认yes
}

PHP-ThinkPHP版本

Nginx配置

server {
    listen  80;
    server_name  localhost;
    root   D:/z-blog/public;
    location / {
        index  index.html index.htm index.php;
        if (!-e $request_filename) {
            rewrite  ^(.*)$  /index.php?s=/$1  last;
            break;
        }
    }

    location ~ \.php(.*)$ {
        fastcgi_pass   127.0.0.1:9500;
        fastcgi_index  index.php;
        fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO  $fastcgi_path_info;
        fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
        include        fastcgi_params;
    }

    location /file {
        internal;
        alias D:/file;
    }
}

ThinkPHP代码

Router:

Route::get('/f/:fileName', 'index/File/file');

Controller:

<?php

namespace app\index\controller;

use think\Request;

class File {
    public function file($fileName) {
        $request = Request::instance();
        $referer = $request->header('referer');
        if (!$referer || strpos($referer, 'https://www.zhangbj.com') !== 0) {
            header("Status:403 Forbidden");
            return;
        }
        header('Content-type: application/octet-stream');
        header("Content-Disposition: attachment; filename=$fileName");
        header("X-Accel-Redirect:  /file/$fileName");
    }
}

参考

Nginx: X-Accel-Redirect

Nginx: XSendfile

Servers 相关文章推荐
Filebeat 采集 Nginx 日志的方法
Mar 31 Servers
Nginx+SpringBoot实现负载均衡的示例
Mar 31 Servers
扩展多台相同的Web服务器
Apr 01 Servers
nginx服务器的下载安装与使用详解
Aug 02 Servers
Nginx配置之实现多台服务器负载均衡
Aug 02 Servers
详解nginx location指令
Jan 18 Servers
Apache Hudi集成Spark SQL操作hide表
Mar 31 Servers
微信告警的zabbix监控系统 监控整个NGINX集群
Apr 18 Servers
nginx 添加http_stub_status_module模块
May 25 Servers
Tomcat 与 maven 的安装与使用教程
Jun 16 Servers
云服务器部署 Web 项目的实现步骤
Jun 28 Servers
Nginx配置使用详解
Jul 07 Servers
Nginx工作原理和优化总结。
利用Nginx代理如何解决前端跨域问题详析
Apr 02 #Servers
Nginx URL重写rewrite机制原理及使用实例
Apr 01 #Servers
nginx限制并发连接请求数的方法
Apr 01 #Servers
Nginx已编译的nginx-添加新模块
Nginx下配置Https证书详细过程
详解Nginx启动失败的几种错误处理
Apr 01 #Servers
You might like
PHP syntax error, unexpected $end 错误的一种原因及解决
2008/10/25 PHP
PHP 事务处理数据实现代码
2010/05/13 PHP
jQuery+php实现ajax文件即时上传的详解
2013/06/17 PHP
PHP判断一个gif图片是否为动态图片的方法
2014/11/19 PHP
PHP中的Trait 特性及作用
2016/04/03 PHP
PHP数组中头部和尾部添加元素的方法(array_unshift,array_push)
2017/04/10 PHP
仿校内登陆框,精美,给那些很厉害但是没有设计天才的程序员
2008/11/24 Javascript
jQuery+CSS 实现的超Sexy下拉菜单
2010/01/17 Javascript
比较搞笑的js陷阱题
2010/02/07 Javascript
Java 正则表达式学习总结和一些小例子
2012/09/13 Javascript
js获取当前日期代码适用于网页头部
2013/06/27 Javascript
JQuery教学之性能优化
2014/05/14 Javascript
window.print打印指定div指定网页指定区域的方法
2014/08/04 Javascript
基于javascript的COOkie的操作实现只能点一次
2014/12/26 Javascript
jquery分割字符串的方法
2015/06/24 Javascript
js实现超简单的展开、折叠目录代码
2015/08/28 Javascript
javascript实现日期时间动态显示示例代码
2015/09/08 Javascript
JS声明式函数与赋值式函数实例分析
2016/12/13 Javascript
JS中parseInt()和map()用法分析
2016/12/16 Javascript
详解Node.js amqplib 连接 Rabbit MQ最佳实践
2019/01/24 Javascript
简单了解微信小程序的目录结构
2019/07/01 Javascript
微信小程序地图绘制线段并且测量(实例代码)
2020/01/02 Javascript
node.js中module模块的功能理解与用法实例分析
2020/02/14 Javascript
javascript使用Blob对象实现的下载文件操作示例
2020/04/18 Javascript
[01:22:42]2014 DOTA2华西杯精英邀请赛 5 24 DK VS LGD
2014/05/26 DOTA
Python面向对象编程基础解析(一)
2017/10/26 Python
python 中if else 语句的作用及示例代码
2018/03/05 Python
selenium+python自动化测试之环境搭建
2019/01/23 Python
python 判断矩阵中每行非零个数的方法
2019/01/26 Python
CSS3旋转——彩色扇子兼容firefox浏览器
2013/06/04 HTML / CSS
菲律宾酒店预订网站:Hotels.com菲律宾
2017/07/12 全球购物
市场部规章制度
2014/01/24 职场文书
搞笑获奖感言
2014/01/30 职场文书
教学改革问题查摆整改措施
2014/09/27 职场文书
破坏寝室公物检讨书
2014/11/17 职场文书
2015年妇女工作总结
2015/05/14 职场文书